wxwoo's blog

原题目链接

洛谷随机跳题跳到的

有指向,有修改,求最小:明显的最小费用最大流

我们将每个格子看成一个点,然后拆点,如下建边:

  1. 源点向每个点连边,流量为1,费用为0

  2. 每个点的拆点向汇点连边,流量为1,费用为0

  3. 每个点向四周的点连边,流量为1,默认指向费用为0,其他为1

下面我们思考这样建边的正确性

根据最小费用最大流的性质,一定会优先费用为0的边(也就是默认指向)

由于每条边流量都是1,所以不存在一个点有两个指向这种情况

ps:3,4数据点疑似在Windows下生成,使用getchar()要注意对\r的判断

代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define inf 1e9
const int N=3e5+1;
struct edge
{
int from,to,next,cap,flow,cost;
}e[N];
bool vis[N];
int cnt,n,m,sour,sink,head[N],ans,cost,q[N],p[N],d[N],h,t;
const int move[4][2]={-1,0,1,0,0,-1,0,1};
inline void add(int u,int v,int l,int f)
{
e[++cnt]=(edge){u,v,head[u],l,0,f};
head[u]=cnt;
e[++cnt]=(edge){v,u,head[v],0,0,-f};
head[v]=cnt;
}
inline void augment()
{
int detla=inf,c=0;
for(int i=sink;i!=sour;i=e[p[i]].from)
{
detla=min(detla,e[p[i]].cap-e[p[i]].flow);
c+=e[p[i]].cost;
}
for(int i=sink;i!=sour;i=e[p[i]].from)
{
e[p[i]].flow+=detla;
e[((p[i]-1)^1)+1].flow-=detla;
}
ans+=detla;
cost+=detla*c;
}
inline bool find()
{
memset(d,127,sizeof(d));
memset(vis,0,sizeof(vis));
vis[sour]=true;
d[sour]=0;
q[h=t=1]=sour;
while(h<=t)
{
int x=q[h++];
vis[x]=false;
for(int i=head[x];i;i=e[i].next)
{
if(e[i].cap>e[i].flow&&d[x]+e[i].cost<d[e[i].to])
{
if(!vis[e[i].to])
{
vis[e[i].to]=true;
q[++t]=e[i].to;
}
d[e[i].to]=d[x]+e[i].cost;
p[e[i].to]=i;
}
}
}
return d[sink]<inf;
}
inline void sap()
{
while(find())
augment();
}
inline void read(int &x)
{
char ch;
int f=1;
x=0;
do
{
if(ch=='-')
f=-1;
ch=getchar();
}while(!('0'<=ch&&ch<='9'));
do
{
x=(x<<3)+(x<<1)+ch-48;
ch=getchar();
}while('0'<=ch&&ch<='9');
x*=f;
}
inline int get(int x,int y)
{
return (x-1)*m+y;
}
int main()
{
read(n);
read(m);
sour=0;
sink=2*n*m+1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
char c;
cin>>c;
int dir;
add(sour,get(i,j),1,0);
add(get(i,j)+n*m,sink,1,0);
if(c=='U')
dir=0;
else if(c=='D')
dir=1;
else if(c=='L')
dir=2;
else if(c=='R')
dir=3;
for(int k=0;k<4;k++)
{
int x=i+move[k][0],y=j+move[k][1];
if(x==n+1)
x=1;
else if(x==0)
x=n;
if(y==m+1)
y=1;
else if(y==0)
y=m;
if(dir==k)
add(get(i,j),get(x,y)+n*m,1,0);
else
add(get(i,j),get(x,y)+n*m,1,1);
}
}
}
sap();
printf("%d",cost);
return 0;
}

 评论

载入天数...载入时分秒...


博客内容遵循 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议

本站使用 Material X 作为主题 , 总访问量为 次 。