题意:
输入一个字符矩阵,'.'代表洞,'#'代表草地。可以把草改成洞花费为d,或者把洞改成草花费为f,最后还要在草和洞之间修围栏花费为b。
但要保证最外一圈是草,求最小费用。
分析:
还不是特别理解紫书上的讲解。。
首先把最外一圈的洞变成草,并累加花费。
增加一个源点和一个汇点,源点连接每个草地,汇点连接每个洞。
源点与最外一圈的草地连一条容量无穷大的边,与其他草地连一条容量为d的边。表示把这条弧切断,割的容量增加d,草就会变成洞。
每个洞与汇点连一条容量为f的边。
相邻两个格子之间连一条双向边。
用最大流算法求最小割在加上之前把边界上的洞变成草的费用,就是最小花费。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 50 * 50 + 10; 6 const int INF = 1000000000; 7 8 struct Edge 9 { 10 int from, to, cap, flow; 11 }; 12 13 bool operator < (const Edge& a, const Edge& b) 14 { return a.from < b.from || ( a.from == b.from && a.to < b.to ); } 15 16 struct Dinic 17 { 18 int n, m, s, t; 19 vector<Edge> edges; 20 vector<int> G[maxn]; 21 bool vis[maxn]; //BFS 22 int d[maxn]; //起点到i的距离 23 int cur[maxn]; //当前弧指针 24 25 int Init(int n) 26 { 27 for(int i = 0; i < n; ++i) G[i].clear(); 28 edges.clear(); 29 } 30 31 void AddEdge(int from, int to, int cap) 32 { 33 edges.push_back(Edge{from, to, cap, 0}); 34 edges.push_back(Edge{to, from, 0, 0}); 35 m = edges.size(); 36 G[from].push_back(m-2); 37 G[to].push_back(m-1); 38 } 39 40 bool BFS() 41 { 42 memset(vis, false, sizeof(vis)); 43 queue<int> Q; 44 Q.push(s); 45 vis[s] = true; 46 d[s] = 0; 47 while(!Q.empty()) 48 { 49 int x = Q.front(); Q.pop(); 50 for(int i = 0; i < G[x].size(); ++i) 51 { 52 Edge& e = edges[G[x][i]]; 53 if(!vis[e.to] && e.cap > e.flow) 54 { 55 vis[e.to] = true; 56 d[e.to] = d[x] + 1; 57 Q.push(e.to); 58 } 59 } 60 } 61 return vis[t]; 62 } 63 64 int DFS(int x, int a) 65 { 66 if(x == t || a == 0) return a; 67 int flow = 0, f; 68 for(int& i = cur[x]; i < G[x].size(); ++i) 69 { 70 Edge& e = edges[G[x][i]]; 71 if(d[x] + 1 ==d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0) 72 { 73 e.flow += f; 74 edges[G[x][i]^1].flow -= f; 75 flow += f; 76 a -= f; 77 if(a == 0) break; 78 } 79 } 80 return flow; 81 } 82 83 int MaxFlow(int s, int t) 84 { 85 this->s = s; this->t = t; 86 int flow = 0; 87 while(BFS()) 88 { 89 memset(cur, 0, sizeof(cur)); 90 flow += DFS(s, INF); 91 } 92 return flow; 93 } 94 }g; 95 96 int w, h; 97 char pool[99][99]; 98 99 inline int ID(int i, int j) { return i*w+j; } 100 101 int main() 102 { 103 //freopen("in.txt", "r", stdin); 104 105 int T, d, f, b; 106 scanf("%d", &T); 107 while(T--) 108 { 109 scanf("%d%d%d%d%d", &w, &h, &d, &f, &b); 110 for(int i = 0; i < h; ++i) scanf("%s", pool[i]); 111 int cost = 0; 112 for(int i = 0; i < h; ++i)//把边上的洞填成草 113 { 114 if(pool[i][0] == '.') { pool[i][0] = '#'; cost += f; } 115 if(pool[i][w-1] == '.') { pool[i][w-1] = '#'; cost += f; } 116 } 117 for(int i = 0; i < w; ++i) 118 { 119 if(pool[0][i] == '.') { pool[0][i] = '#'; cost += f; } 120 if(pool[h-1][i] == '.') { pool[h-1][i] = '#'; cost += f; } 121 } 122 123 g.Init(h*w+2); 124 for(int i = 0; i < h; i++) 125 for(int j = 0; j < w; j++) 126 { 127 if(pool[i][j] == '#') 128 { 129 int cap = d; 130 if(i == 0 || i == h-1 || j == 0 || j == w-1) cap = INF; 131 g.AddEdge(w*h, ID(i, j), cap); 132 } 133 else 134 { 135 g.AddEdge(ID(i, j), w*h+1, f); 136 } 137 if(i > 0) g.AddEdge(ID(i, j), ID(i-1, j), b); 138 if(i < h-1) g.AddEdge(ID(i, j), ID(i+1, j), b); 139 if(j > 0) g.AddEdge(ID(i, j), ID(i, j-1), b); 140 if(j < w-1) g.AddEdge(ID(i, j), ID(i, j+1), b); 141 } 142 143 printf("%d\n", cost + g.MaxFlow(w*h, w*h+1)); 144 } 145 146 return 0; 147 }