题目大意:给定一个m*n的矩阵,每个位置如果作为商业区或者工业区各有一个收益,如果相邻两块是不同的也会有一个收益,求最大收益
吐槽:住宅区呢- - 地理老师骗我们- -
普通的最小割建图会遇到一个问题:
割断两块之间的边收益为正,即代价为负
因此我们如果正常建最小割,那么两块之间的边权就会是负的
那么我们将这个矩阵黑白染色,将白格ST反向
这样割断两块之间的连边相当于两块选择了同一用途,代价为正
就可以正常跑了
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 10100 #define P(x,y) ((x)*n-n+(y)) #define S 0 #define T (m*n+1) #define INF 0x3f3f3f3f using namespace std; int m,n,ans; const int dx[]={1,-1,0,0}; const int dy[]={0,0,1,-1}; namespace Max_Flow{ struct abcd{ int to,f,next; }table[1001001]; int head[M],tot=1; int dpt[M]; void Add(int x,int y,int z) { table[++tot].to=y; table[tot].f=z; table[tot].next=head[x]; head[x]=tot; } void Link(int x,int y,int z) { Add(x,y,z); Add(y,x,z); } bool BFS() { static int q[M]; int i,r=0,h=0; memset(dpt,-1,sizeof dpt); dpt[S]=1;q[++r]=S; while(r!=h) { int x=q[++h]; for(i=head[x];i;i=table[i].next) if(table[i].f&&!~dpt[table[i].to]) { dpt[table[i].to]=dpt[x]+1; q[++r]=table[i].to; if(table[i].to==T) return true; } } return false; } int Dinic(int x,int flow) { int i,left=flow; if(x==T) return flow; for(i=head[x];i&&left;i=table[i].next) if(table[i].f&&dpt[table[i].to]==dpt[x]+1) { int temp=Dinic(table[i].to,min(left,table[i].f) ); left-=temp; table[i].f-=temp; table[i^1].f+=temp; } if(left) dpt[x]=-1; return flow-left; } } int main() { using namespace Max_Flow; int i,j,k,x; cin>>m>>n; for(i=1;i<=m;i++) for(j=1;j<=n;j++) { scanf("%d",&x); ans+=x; if(i+j&1) Link(S,P(i,j),x); else Link(P(i,j),T,x); } for(i=1;i<=m;i++) for(j=1;j<=n;j++) { scanf("%d",&x); ans+=x; if(~(i+j)&1) Link(S,P(i,j),x); else Link(P(i,j),T,x); } for(i=1;i<=m;i++) for(j=1;j<=n;j++) { scanf("%d",&x); for(k=0;k<4;k++) { int xx=i+dx[k]; int yy=j+dy[k]; if(xx<=0||yy<=0||xx>m||yy>n) continue; ans+=x; Link(P(i,j),P(xx,yy),x); } } while( BFS() ) ans-=Dinic(S,INF); cout<<ans<<endl; return 0; }
时间: 2024-10-05 04:59:14