【UVA1515 算法竞赛入门指南】 水塘【最小割】

题意:

  输入一个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\n",ans);
121     }
122 return 0;
123 }
View Code

 

posted @ 2018-07-13 16:06  蒟蒻LQL  阅读(420)  评论(0编辑  收藏  举报