【BZOJ4439】[Swerc2015]Landscaping 最小割
【BZOJ4439】[Swerc2015]Landscaping
Description
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
题解:同【BZOJ2768】[JLOI2010]冠军调查,三倍经验~
#include <cstdio> #include <iostream> #include <cstring> #include <queue> #define P(X,Y) ((X-1)*m+Y) using namespace std; int n,m,cnt,ans,S,T,A,B; int to[300000],next[300000],val[300000],head[3000],d[3000]; int dx[]={0,1,0,-1},dy[]={1,0,-1,0}; char str[60]; queue<int> q; int dfs(int x,int mf) { if(x==T) return mf; int i,k,temp=mf; for(i=head[x];i!=-1;i=next[i]) { if(d[to[i]]==d[x]+1&&val[i]) { k=dfs(to[i],min(temp,val[i])); if(!k) d[to[i]]=0; val[i]-=k,val[i^1]+=k,temp-=k; if(!temp) break; } } return mf-temp; } int bfs() { memset(d,0,sizeof(d)); while(!q.empty()) q.pop(); d[S]=1,q.push(S); int i,u; while(!q.empty()) { u=q.front(),q.pop(); for(i=head[u];i!=-1;i=next[i]) { if(!d[to[i]]&&val[i]) { d[to[i]]=d[u]+1; if(to[i]==T) return 1; q.push(to[i]); } } } return 0; } void add(int a,int b,int c) { to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++; to[cnt]=a,val[cnt]=0,next[cnt]=head[b],head[b]=cnt++; } int main() { scanf("%d%d%d%d",&n,&m,&A,&B); int i,j,k; S=0,T=n*m+1; memset(head,-1,sizeof(head)); for(i=1;i<=n;i++) { scanf("%s",str); for(j=1;j<=m;j++) { if(str[j-1]=='#') add(S,P(i,j),B); else add(P(i,j),T,B); for(k=0;k<4;k++) if(i+dx[k]&&i+dx[k]<=n&&j+dy[k]&&j+dy[k]<=m) add(P(i,j),P(i+dx[k],j+dy[k]),A); } } while(bfs()) ans+=dfs(S,1<<30); printf("%d",ans); return 0; }
| 欢迎来原网站坐坐! >原文链接<