如果不允许转化'#'和'.'的话,那么可以直接在'#'和'.'之间连容量为b的边,把所有'#'和一个源点连接,
所有'.'和一个汇点连接,流量不限,那么割就是建围栏(分割'#'和'.')的花费。
问题是'#'和'.'是可以转化的,由刚才的思路,可以联想到,当'#'可以转化成'.'的时候,那么就不需要在它和周围的'.'之间建围栏,
那么可以限制源点到'#'的容量为d,表示最多花费为d,对称地,限制'.'到汇点T容量为f。
然后跑最大流最小割就好了。
这题思路好神啊。。。仔细体会容量表示最多花费和最小割的关系
#include<bits/stdc++.h> using namespace std; struct Edge { int v,cap,nxt; }; const int maxv = 2502+6; vector<Edge> edges; #define PB push_back int head[maxv],cur[maxv]; void AddEdge(int u,int v,int c) { edges.PB({v,c,head[u]}); head[u] = edges.size()-1; edges.PB({u,0,head[v]}); head[v] = edges.size()-1; } int S = 0,T = 1; int lv[maxv]; bool vis[maxv]; int q[maxv]; bool bfs() { memset(vis,0,sizeof(vis)); int l = 0, r = 0; lv[S] = 0; q[r++] = S; vis[S] = true; while(r>l){ int u = q[l++]; for(int i = head[u]; ~i; i = edges[i].nxt){ Edge &e = edges[i]; if(!vis[e.v] && e.cap){ lv[e.v] = lv[u]+1; vis[e.v] = true; q[r++] = e.v; } } } return vis[T]; } int dfs(int u,int a) { if(u == T||!a) return a; int flow = 0,f; for(int &i = cur[u]; ~i; i = edges[i].nxt){ Edge &e = edges[i]; if(lv[e.v] == lv[u]+1 && (f = dfs(e.v,min(a,e.cap)))){ flow += f; e.cap -= f; edges[i^1].cap += f; a -= f; if(!a) break; } } return flow; } const int INF = 0x3f3f3f3f; int MaxFlow() { int flow = 0; while(bfs()){ memcpy(cur,head,sizeof(head)); flow += dfs(S,INF); } return flow; } const int N = 50; char g[N][N+2]; int id[N][N]; int h,w; int d,f,b; int ID(int i,int j) { return i*w+j+2; } void init() { scanf("%d%d%d%d%d",&w,&h,&d,&f,&b); edges.clear(); for(int i = 0; i < h; i++){ scanf("%s",g[i]); for(int j = 0; j < w; j++){ id[i][j] = ID(i,j); } } memset(head,-1,sizeof(head)); } int dx[] = {0,0,1,-1}; int dy[] = {1,-1,0,0}; int main() { //freopen("in.txt","r",stdin); int TestCase; scanf("%d",&TestCase); while(TestCase--){ init(); int cost = 0; for(int i = 0; i < h; i++){ for(int j = 0; j < w; j++){ if(i == 0 || i == h-1 || j == 0|| j == w-1){ if(g[i][j] == '.') cost += f; AddEdge(S,id[i][j],INF); }else { if(g[i][j] == '#') AddEdge(S,id[i][j],d); else AddEdge(id[i][j],T,f); } for(int k = 0; k < 4; k++){ int ni = i+dx[k], nj = j+dy[k]; if(ni<0||ni>=h||nj<0||nj>=w) continue; AddEdge(id[i][j],id[ni][nj],b); } } } printf("%d ",cost+MaxFlow()); } return 0; }