输入一个字符矩阵,'.'代表洞,'#'代表草地。可以把草改成洞花费为d,或者把洞改成草花费为f,最后还要在草和洞之间修围栏花费为b。
首先把最外一圈的洞变成草,并累加花费。
增加一个源点和一个汇点,源点连接每个草地,汇点连接每个洞。
源点与最外一圈的草地连一条容量无穷大的边,与其他草地连一条容量为d的边。表示把这条弧切断,割的容量增加d,草就会变成洞。
每个洞与汇点连一条容量为f的边。
相邻两个格子之间连一条双向边。
用最大流算法求最小割在加上之前把边界上的洞变成草的费用,就是最小花费。
用最小的费用将对象划分成两个集合的问题常常可以转换成最小割顺利解决.这道题就可以考虑将每一个点变成草地和洞分成两个集合.
如果通过合适的建边使得花费的总和等价于割的容量的话,那么为了求最小花费只要求最小割就好.
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <vector> 5 #include <cstring> 6 #include <string> 7 #include <algorithm> 8 #include <string> 9 #include <set> 10 #include <functional> 11 #include <numeric> 12 #include <sstream> 13 #include <stack> 14 #include <map> 15 #include <queue> 16 #pragma comment(linker, "/STACK:102400000,102400000") 17 #define CL(arr, val) memset(arr, val, sizeof(arr)) 18 19 #define ll long long 20 #define inf 0x7f7f7f7f 21 #define lc l,m,rt<<1 22 #define rc m + 1,r,rt<<1|1 23 #define pi acos(-1.0) 24 25 #define L(x) (x) << 1 26 #define R(x) (x) << 1 | 1 27 #define MID(l, r) (l + r) >> 1 28 #define Min(x, y) (x) < (y) ? (x) : (y) 29 #define Max(x, y) (x) < (y) ? (y) : (x) 30 #define E(x) (1 << (x)) 31 #define iabs(x) (x) < 0 ? -(x) : (x) 32 #define OUT(x) printf("%I64d ", x) 33 #define lowbit(x) (x)&(-x) 34 #define Read() freopen("a.txt", "r", stdin) 35 #define Write() freopen("b.txt", "w", stdout); 36 #define maxn 1010 37 #define maxv 3000 38 #define mod 1000000000 39 using namespace std; 40 41 struct edge 42 { 43 int to,cap,rev; 44 edge(){} 45 edge(int x,int y,int z) 46 { 47 to=x; 48 cap=y; 49 rev=z; 50 } 51 }; 52 53 vector<edge>G[maxv]; 54 int level[maxv]; 55 int iter[maxv]; 56 57 void Add_Edge(int from,int to,int cap) 58 { 59 G[from].push_back((edge){to,cap,G[to].size()}); 60 G[to].push_back((edge){from,0,G[from].size()-1}); 61 } 62 63 void bfs(int s) 64 { 65 memset(level,-1,sizeof(level)); 66 queue<int>que; 67 level[s]=0; 68 que.push(s); 69 while(!que.empty()) 70 { 71 int v=que.front();que.pop(); 72 for(int i=0;i<G[v].size();i++) 73 { 74 edge &e=G[v][i]; 75 if(e.cap>0&&level[e.to]<0) 76 { 77 level[e.to]=level[v]+1; 78 que.push(e.to); 79 } 80 } 81 } 82 } 83 int dfs(int v,int t,int f) 84 { 85 if(v==t) return f; 86 for(int &i=iter[v];i<G[v].size();i++) 87 { 88 edge &e=G[v][i]; 89 if(e.cap>0&&level[v]<level[e.to]) 90 { 91 int d=dfs(e.to,t,min(f,e.cap)); 92 if(d>0) 93 { 94 e.cap-=d; 95 G[e.to][e.rev].cap+=d; 96 // printf("%d %d %d ",e.to,e.rev,G[e.to][e.rev]); 97 return d; 98 } 99 } 100 } 101 return 0; 102 } 103 104 int max_flow(int s,int t) 105 { 106 int flow=0; 107 for(;;) 108 { 109 bfs(s); 110 if(level[t]<0) return flow; 111 memset(iter,0,sizeof(iter)); 112 int f; 113 while((f=dfs(s,t,inf))>0) 114 flow+=f; 115 } 116 } 117 char s[55][55]; 118 int w,h; 119 int ID(int i,int j) 120 { 121 return i*w+j; 122 } 123 int main() 124 { 125 //freopen("a.txt","r",stdin); 126 int t,d,f,b; 127 scanf("%d",&t); 128 while(t--) 129 { 130 scanf("%d%d%d%d%d",&w,&h,&d,&f,&b); 131 for(int i=0;i<w*h+2;i++) 132 G[i].clear(); 133 for(int i=0;i<h;i++) 134 { 135 scanf("%s",s[i]); 136 } 137 int cost=0; 138 for(int i=0;i<h;i++) 139 { 140 if(s[i][0]=='.') {s[i][0]='#';cost+=f;} 141 if(s[i][w-1]=='.') {s[i][w-1]='#';cost+=f;} 142 } 143 for(int i=0;i<w;i++) 144 { 145 if(s[0][i]=='.') {s[0][i]='#';cost+=f;} 146 if(s[h-1][i]=='.'){s[h-1][i]='#';cost+=f;} 147 } 148 for(int i=0;i<h;i++) 149 { 150 for(int j=0;j<w;j++) 151 { 152 if(s[i][j]=='#') 153 { 154 int cap=inf; 155 if(i>0&&i<h-1&&j>0&&j<w-1) cap=d; 156 Add_Edge(w*h,ID(i,j),cap); 157 if(i>0) {Add_Edge(ID(i,j),ID(i-1,j),b);} 158 if(i<h-1) {Add_Edge(ID(i,j),ID(i+1,j),b);} 159 if(j>0) {Add_Edge(ID(i,j),ID(i,j-1),b);} 160 if(j<w-1) {Add_Edge(ID(i,j),ID(i,j+1),b);} 161 } 162 else 163 { 164 Add_Edge(ID(i,j),w*h+1,f); 165 if(i>0) {Add_Edge(ID(i,j),ID(i-1,j),b);} 166 if(i<h-1) {Add_Edge(ID(i,j),ID(i+1,j),b);} 167 if(j>0) {Add_Edge(ID(i,j),ID(i,j-1),b);} 168 if(j<w-1) {Add_Edge(ID(i,j),ID(i,j+1),b);} 169 } 170 } 171 } 172 printf("%d ",cost+max_flow(w*h,w*h+1)); 173 } 174 return 0; 175 }