【BZOJ 2132】 圈地计划

来源:互联网 发布:mac强制退出 快捷键 编辑:程序博客网 时间:2024/04/28 19:02

2132: 圈地计划

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 382  Solved: 271
[Submit][Status][Discuss]

Description

最近房地产商GDOI(Group of Dumbbells Or Idiots)从NOI(Nuts Old Idiots)手中得到了一块开发土地。据了解,这块土地是一块矩形的区域,可以纵横划分为N×M块小区域。GDOI要求将这些区域分为商业区和工业区来开发。根据不同的地形环境,每块小区域建造商业区和工业区能取得不同的经济价值。更具体点,对于第i行第j列的区域,建造商业区将得到Aij收益,建造工业区将得到Bij收益。另外不同的区域连在一起可以得到额外的收益,即如果区域(I,j)相邻(相邻是指两个格子有公共边)有K块(显然K不超过4)类型不同于(I,j)的区域,则这块区域能增加k×Cij收益。经过Tiger.S教授的勘察,收益矩阵A,B,C都已经知道了。你能帮GDOI求出一个收益最大的方案么?

Input

输入第一行为两个整数,分别为正整数N和M,分别表示区域的行数和列数;第2到N+1列,每行M个整数,表示商业区收益矩阵A;第N+2到2N+1列,每行M个整数,表示工业区收益矩阵B;第2N+2到3N+1行,每行M个整数,表示相邻额外收益矩阵C。第一行,两个整数,分别是n和m(1≤n,m≤100);

Output

输出只有一行,包含一个整数,为最大收益值。

Sample Input

3 3
1 2 3
4 5 6
7 8 9
9 8 7
6 5 4
3 2 1
1 1 1
1 3 1
1 1 1

Sample Output

81
【数据规模】
对于100%的数据有N,M≤100

最小割建模。


要求收益最大,但是最小割是最小,所以肯定是用总收益减去最小的不可行收益。


如果两个相邻格子颜色一样,是需要被减掉的。


但是最小割中x与y连边,如果xy不在同一集合才会产生代价,因此我们需要把这块土地黑白染色,黑色格子属于s集表示商业区,白色格子属于s集表示工业区。


因此,黑白染色,然后就是最小割的基本建模了。


#include <iostream>#include <cstring>#include <algorithm>#include <queue>#include <cstdio>#include <cstdlib>#define M 100+5#define N 20000+5#define inf 0x3f3f3f3fusing namespace std;int tot=1,s,t,h[N],cur[N],d[N],v[N],num[M][M],c[M][M],n,m,A[M][M],B[M][M],C[M][M];int fx[6][3];struct edge{int from,to,cap,flow,ne;}E[200005];void Addedge(int from,int to,int cap){E[++tot]=(edge){from,to,cap,0,h[from]};h[from]=tot;E[++tot]=(edge){to,from,0,0,h[to]};h[to]=tot;}bool bfs(){for (int i=s;i<=t;i++)v[i]=0;v[s]=1;d[s]=0;queue<int> q;q.push(s);while (!q.empty()){int x=q.front();q.pop();for (int i=h[x];i;i=E[i].ne){edge e=E[i];if (!v[e.to]&&e.cap>e.flow){v[e.to]=1;d[e.to]=d[x]+1;q.push(e.to);}}}return v[t];}int dfs(int x,int a){if (x==t||!a) return a;int flow=0;for (int &i=cur[x];i;i=E[i].ne){edge &e=E[i];if (d[e.to]!=d[x]+1) continue;int f=dfs(e.to,min(a,e.cap-e.flow));if (f){e.flow+=f;E[i^1].flow-=f;flow+=f;a-=f;if (!a) break;}}return flow;}int dinic(){int flow=0;while (bfs()){for (int i=s;i<=t;i++)cur[i]=h[i];flow+=dfs(s,inf);}return flow;}void Paint(){for (int i=1;i<=m;i++)c[0][i]=1^c[0][i-1];for (int i=1;i<=n;i++)for (int j=1;j<=m;j++)c[i][j]=1^c[i-1][j],num[i][j]=(i-1)*m+j;}int main(){    scanf("%d%d",&n,&m);for (int i=1;i<=n;i++)for (int j=1;j<=m;j++)scanf("%d",&A[i][j]);for (int i=1;i<=n;i++)for (int j=1;j<=m;j++)scanf("%d",&B[i][j]);for (int i=1;i<=n;i++)for (int j=1;j<=m;j++)scanf("%d",&C[i][j]);Paint();s=0,t=n*m+1;int ans=0;for (int i=1;i<=n;i++)for (int j=1;j<=m;j++){if (c[i][j])Addedge(s,num[i][j],A[i][j]),Addedge(num[i][j],t,B[i][j]);elseAddedge(s,num[i][j],B[i][j]),Addedge(num[i][j],t,A[i][j]);ans+=(A[i][j]+B[i][j]);}fx[1][1]=fx[2][1]=0,fx[1][2]=1,fx[2][2]=-1;fx[3][2]=fx[4][2]=0,fx[3][1]=1,fx[4][1]=-1;for (int i=1;i<=n;i++)for (int j=1;j<=m;j++){for (int k=1;k<=4;k++){int nx=i+fx[k][1],ny=j+fx[k][2];if (nx<1||ny<1||nx>n||ny>m) continue;int x=C[i][j]+C[nx][ny];ans+=C[i][j];Addedge(num[i][j],num[nx][ny],x);}}printf("%d\n",ans-dinic());return 0;}


1 0
原创粉丝点击