题意:
输入一个h行w列的字符矩阵,草地用“#”表示,洞用"."表示。你可以把草改成洞,每格花费为d,也可以把洞填上草,每格花费为f。最后还需要在草和洞之间修围栏,每条边花费为b。整个矩阵第一行/列和最后一行列必须是草。求最小花费。
分析
这是一个最小割的很典型的题目。
每个洞要么是草地,要么是洞,我们假设草地是S集合,洞是Y集合,然后洞和草之间要建栅栏,也就可以理解为,用最少的花费将S集合和Y集合分开,这就是最小割的模型了。初始时,从s点向所有的草地点连一条边,容量为d,割这些边意味着将这个草地变成洞。把每个洞的点向t连一条边,容量为f,割这些边意味着将这个洞变成草。相邻的两个格子之间u和v,连两条边,u到v和 v到u,容量为b。割u到v这条边意味着u是草,v是洞,在之间建围栏。割v到u的点也类似。
题目还有一个要求,矩阵第一行/列和最后一行/列必须是草,所以,s向这些草连边容量为INF,代表这些边不能割。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <queue> 6 7 using namespace std; 8 const int maxn=3000+10; 9 const int maxw=55; 10 const int maxm=30000; 11 const int INF=2147000000; 12 struct Dinic{ 13 int head[maxn],Next[maxm],to[maxm],cap[maxm],flow[maxm]; 14 int sz,n,m,s,t; 15 bool vis[maxn]; 16 int cur[maxn],d[maxn]; 17 void init(int n){ 18 this->n=n; 19 memset(head,-1,sizeof(head)); 20 sz=-1; 21 } 22 void add_edge(int a,int b,int c){ 23 ++sz; 24 to[sz]=b; 25 cap[sz]=c;flow[sz]=0; 26 Next[sz]=head[a];head[a]=sz; 27 ++sz; 28 to[sz]=a; 29 cap[sz]=c;flow[sz]=c; 30 Next[sz]=head[b];head[b]=sz; 31 } 32 bool BFS(){ 33 memset(vis,0,sizeof(vis)); 34 queue<int>Q; 35 vis[s]=1; 36 d[s]=0; 37 Q.push(s); 38 while(!Q.empty()){ 39 int u=Q.front();Q.pop(); 40 for(int i=head[u];i!=-1;i=Next[i]){ 41 int v=to[i]; 42 if(!vis[v]&&cap[i]>flow[i]){ 43 vis[v]=1; 44 d[v]=d[u]+1; 45 Q.push(v); 46 } 47 } 48 } 49 return vis[t]; 50 } 51 int DFS(int x,int a){ 52 if(x==t||a==0)return a; 53 int Flow=0,f; 54 for(int& i=cur[x];i!=-1;i=Next[i]){ 55 int v=to[i]; 56 if(d[v]==d[x]+1&&(f=DFS(v,min(a,cap[i]-flow[i])))>0){ 57 Flow+=f; 58 flow[i]+=f; 59 flow[i^1]-=f; 60 a-=f; 61 if(a==0)break; 62 } 63 } 64 return Flow; 65 } 66 int Maxflow(int s,int t){ 67 this->s=s,this->t=t; 68 int Flow=0; 69 while(BFS()){ 70 for(int i=0;i<=n;i++) 71 cur[i]=head[i]; 72 Flow+=DFS(s,INF); 73 } 74 return Flow; 75 } 76 }dinic; 77 int w,h,d,f,b,T,ans; 78 char G[maxw][maxw]; 79 int main(){ 80 scanf("%d",&T); 81 for(int t=1;t<=T;t++){ 82 ans=0; 83 scanf("%d%d",&w,&h); 84 scanf("%d%d%d",&d,&f,&b); 85 for(int i=1;i<=h;i++){ 86 for(int j=1;j<=w;j++){ 87 scanf(" %c",&G[i][j]); 88 if(i==1||j==1||i==h||j==w){ 89 if(G[i][j]=='.'){ 90 G[i][j]='#'; 91 ans+=f; 92 } 93 } 94 } 95 } 96 dinic.init(w*h+2); 97 for(int i=1;i<=h;i++){ 98 for(int j=1;j<=w;j++){ 99 if(i==1||j==1||i==h||j==w){ 100 dinic.add_edge(0,(i-1)*w+j,INF); 101 }else{ 102 if(G[i][j]=='#'){ 103 dinic.add_edge(0,(i-1)*w+j,d); 104 } 105 if(G[i][j]=='.'){ 106 dinic.add_edge((i-1)*w+j,h*w+1,f); 107 } 108 } 109 if(i+1<=h){ 110 dinic.add_edge((i-1)*w+j,i*w+j,b); 111 dinic.add_edge(i*w+j,(i-1)*w+j,b); 112 } 113 if(j+1<=w){ 114 dinic.add_edge((i-1)*w+j,(i-1)*w+j+1,b); 115 dinic.add_edge((i-1)*w+j+1,(i-1)*w+j,b); 116 } 117 } 118 } 119 ans+=dinic.Maxflow(0,w*h+1); 120 printf("%d ",ans); 121 } 122 return 0; 123 }