4439: [Swerc2015]Landscaping
Time Limit: 2 Sec Memory Limit: 512 MBDescription
FJ有一块N*M的矩形田地,有两种地形高地(用‘#’表示)和低地(用‘.’表示)
FJ需要对每一行田地从左到右完整开收割机走到头,再对每一列从上到下完整走到头,如下图所示
对于一个4*4的田地,FJ需要走8次。
收割机是要油的,每次从高地到低地或从低地到高地需要支付A的费用。
但是FJ有黑科技,可以高地与低地的互变,都只需要一个支付B的费用。
询问FJ需要支付最小费用。
Input
第一行包含四个整数N,M,A,B,意义如上文所述。
接下来是一个N*M的字符串矩阵,表示农田的地形,’#’表示高地,’.’表示低地。
Output
只包含一个正整数,表示最小费用。
1<=N,M<=50
1<=A,B<=100000
1<=A,B<=100000
Sample Input
5 4 1000 2000
...#
#..#
...#
##..
###.
...#
#..#
...#
##..
###.
Sample Output
11000
样例解释:
把(2,1)的高地变成低地花费2000,燃料花费9000
样例解释:
把(2,1)的高地变成低地花费2000,燃料花费9000
HINT
我们以源点向高处,低处向汇点连权值为 B 的边,在相邻的点连权值为 A 的边,然后跑最小割
#include<map> #include<cmath> #include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define ll long long #define N 100010 int n,m,S,T; inline int pos(int i,int j){return (i-1)*m+j;} char str[100]; int lj[N],to[N],v[N],fro[N],cnt=1; void add(int a,int b,int c){fro[++cnt]=lj[a];to[cnt]=b;v[cnt]=c;lj[a]=cnt;} void ins(int a,int b,int c){add(a,b,c);add(b,a,0);} int q[N],dis[N],l,r; bool bfs() { int x;l=0;r=1; memset(dis,0,sizeof(dis)); dis[S]=1;q[1]=S; while(l!=r) { x=q[l++];if(l==N) l=0; for(int i=lj[x];i;i=fro[i]) { if(v[i]&&!dis[to[i]]) { dis[to[i]]=dis[x]+1; if(to[i]==T) return 1; q[r++]=to[i];if(r==N) r=0; } } } return 0; } int dfs(int x,int p) { if(x==T) return p; int tp,res=0; for(int i=lj[x];i;i=fro[i]) { if(v[i]&&dis[to[i]]==dis[x]+1) { tp=dfs(to[i],min(p-res,v[i])); v[i]-=tp;v[i^1]+=tp; res+=tp; if(res==p) return p; } } if(res==0) dis[x]=0; return res; } int a,b,ans; int main() { scanf("%d%d%d%d",&n,&m,&a,&b); S=0;T=n*m+1; for(int i=1;i<=n;i++) { scanf("%s",str+1); for(int j=1;j<=m;j++) { if(str[j]=='#') ins(S,pos(i,j),b); else ins(pos(i,j),T,b); } } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(i>1) ins(pos(i,j),pos(i-1,j),a); if(i<n) ins(pos(i,j),pos(i+1,j),a); if(j>1) ins(pos(i,j),pos(i,j-1),a); if(j<m) ins(pos(i,j),pos(i,j+1),a); } } while(bfs()) ans+=dfs(S,0x3f3f3f3f); printf("%d ",ans); return 0; }