您的位置:首页 > 理论基础 > 计算机网络

【bzoj 2132】圈地计划(最小割)

2016-04-06 11:33 639 查看
Time Limit: 2 Sec Memory Limit: 256 MB

Submit: 923 Solved: 418

[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);

任何数字不超过1000”的限制

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

**【题解】【网络流,最小割(=最大流)】

【黑白染色,黑点选工业区与源点连边,选商业区与汇点连边,流量为收益;白点选商业区与源点连边,选工业区与汇点连边,流量为收益; 相邻两点之间连边(因为染色本就将它们染成不同的颜色),流量为两点选不同颜色的收益和。别忘了将所有边的流量加起来,最后减去最小割,就是答案】 **

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[1000010],next[1000010],p[200010],remain[1000010],tot;
int dis[200010],cur[200010];
int val[110][110];
int n,m,S,T;
long long mincut,sum,s,ans;

inline void add(int x,int y,int flow)
{
tot++; a[tot]=y; next[tot]=p[x]; p[x]=tot; remain[tot]=flow;
tot++; a[tot]=x; next[tot]=p[y]; p[y]=tot; remain[tot]=0;
}

inline bool bfs(int s,int t)
{
queue<int>que;
memset(dis,-1,sizeof(dis));
for (int i=s;i<=t;++i) cur[i]=p[i];
que.push(s); dis[s]=0;
while (!que.empty())
{
int u,v;
u=que.front(); que.pop();
v=p[u];
while (v!=-1)
{
if (remain[v]&&dis[a[v]]<0)
{
dis[a[v]]=dis[u]+1;
que.push(a[v]);
}
v=next[v];
}
}
if (dis[t]<0) return false;
else return true;
}
inline int dfs(int now,int t,int flow)
{
if (now==t||!flow) return flow;
int u=cur[now],s,s1=0;
while (u!=-1)
{
cur[now]=u;
if (dis[a[u]]==dis[now]+1&&(s=dfs(a[u],t,min(flow,remain[u]))))
{
s1+=s; flow-=s;
remain[u]-=s; remain[u^1]+=s;
if (!flow) break;
}
u=next[u];
}
return s1;
}
int main()
{
int i,j,k;
memset(p,-1,sizeof(p));
memset(next,-1,sizeof(next));
scanf("%d%d",&n,&m);
T=n*m+1; tot=-1;
for (i=1;i<=n;++i)
for (j=1;j<=m;++j)
{
int x,k;
k=(i-1)*m+j;
scanf("%d",&x);
if((i+j)&1) add(S,k,x);
else add(k,T,x);
sum+=x;
}
for (i=1;i<=n;++i)
for (j=1;j<=m;++j)
{
int x,k=(i-1)*m+j;
scanf("%d",&x);
if (!((i+j)&1)) add(S,k,x);
else add(k,T,x);
sum+=x;
}
for (i=1;i<=n;++i)
for (j=1;j<=m;++j)
scanf("%d",&val[i][j]);
for (i=1;i<=n;++i)
for (j=1;j<=m;++j)
{
int k=(i-1)*m+j;
if(i!=1)
add(k,k-m,val[i][j]+val[i-1][j]),sum+=val[i][j];
if(i!=n)
add(k,k+m,val[i][j]+val[i+1][j]),sum+=val[i][j];
if(j!=1)
add(k,k-1,val[i][j]+val[i][j-1]),sum+=val[i][j];
if(j!=m)
add(k,k+1,val[i][j]+val[i][j+1]),sum+=val[i][j];
}
while(bfs(S,T))
while (s=dfs(S,T,0x7fffffff))
mincut+=s;
ans=sum-mincut;
printf("%lld\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  bzoj-网络流