题目链接
分析:紫书上的一道例题,大意就是让你用最小的花费把草和洞分割开。为了让所有的草以及洞连通,我们引入源点S和汇点T,与S相连的都是草,与T相连的都是洞,草和洞是可以相互转化的,所以把草向S连一条容量为d的弧,表示要让草转化成洞需要割掉这条弧,T的也同理。但是我们还要安放栅栏在草和洞之间,所以我们每个结点要向四周相邻结点连一条容量为f的弧,表示如果割掉这一条弧需要支付f的费用,相当于在两个结点之间安放一个栅栏,画画图就可以理解。
#include<bits/stdc++.h>
#define PII pair<int,int>
#define x first
#define y second
#define MAIN main
using namespace std;
typedef long long LL;
const int INF=0x3f3f3f3f;
const int N=3e3+10;
struct edge
{
int u,v,cap,flow;
edge(int u=0,int v=0,int cap=0,int flow=0):u(u),v(v),cap(cap),flow(flow){}
};
vector<edge>E;
vector<int>g[N];
void add(int u,int v,int cap)
{
E.push_back(edge(u,v,cap,0));
E.push_back(edge(v,u,0,0));
int m=E.size();
g[u].push_back(m-2);
g[v].push_back(m-1);
}
int n,m;
int d[N],cur[N],vis[N];
int bfs(int s,int t)
{
memset(vis,0,sizeof(vis));
queue<int>q;
vis[s]=1;d[s]=0;
q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=0;i<(int)g[u].size();i++){
edge &e=E[g[u][i]];
int v=e.v;
if(!vis[v]&&e.cap>e.flow)
{
vis[v]=1;
q.push(v);
d[v]=d[u]+1;
}
}
}
return vis[t];
}
int dfs(int s,int t,int a)
{
if(s==t||a==0) return a;
int flow=0,f;
for(int &i=cur[s];i<(int)g[s].size();i++){
edge &e=E[g[s][i]];
int v=e.v;
if(d[v]==d[s]+1&&(f=dfs(v,t,min(a,e.cap-e.flow)))>0){
flow+=f;
e.flow+=f;
E[g[s][i]^1].flow-=f;
a-=f;
if(a==0) break;
}
}
return flow;
}
int max_flow(int s,int t)
{
int flow=0;
while(bfs(s,t)){
memset(cur,0,sizeof(cur));
flow+=dfs(s,t,INF);
}
return flow;
}
int num(int x,int y){return m*(x-1)+y;}
bool judge(int x,int y)
{
if(x>=1&&x<=n&&y>=1&&y<=m) return true;
return false;
}
char graph[51][51];
int dx[4]={1,-1,0,0};
int dy[4]={0,0,-1,1};
int MAIN()
{
int test;
scanf("%d",&test);
while(test--)
{
scanf("%d%d",&m,&n);
int dd,f,b;
E.clear();
for(int i=0;i<=n*m+1;i++) g[i].clear();
int s=0,t=n*m+1,ans=0;
scanf("%d%d%d",&dd,&f,&b);
for(int i=1;i<=n;i++) scanf("%s",(graph[i]+1));
for(int i=1;i<=n;i++){
if(i==1||i==n){
for(int j=2;j<m;j++){
if(graph[i][j]=='.') ans+=f;
graph[i][j]='#';
add(s,num(i,j),INF);
}
}
else {
for(int j=2;j<m;j++){
if(graph[i][j]=='.') add(num(i,j),t,f);
else add(s,num(i,j),dd);
}
}
if(graph[i][1]=='.') ans+=f;
if(graph[i][m]=='.') ans+=f;
graph[i][1]='#';graph[i][m]='#';
add(s,num(i,1),INF);add(s,num(i,m),INF);
for(int j=1;j<=m;j++){
for(int k=0;k<4;k++){
int nx=i+dx[k];
int ny=j+dy[k];
if(judge(nx,ny)){
add(num(i,j),num(nx,ny),b);
}
}
}
}
ans+=max_flow(s,t);
printf("%d\n",ans);
}
return 0;
}