您的位置:首页 > 其它

[BZOJ2132]圈地计划(最小割)

2016-04-07 19:17 393 查看

题目描述

传送门

题解

抄黄学长的题解。

黑白染色,对于每个黑点A,S->A:W商业,A->T:W工业,对于每个白点B,S->B:W工业,B->T:W商业,对于每对有关系的两点A,B,A<–>B:c1+c2。

这个建模感受一下就是对的。

看黄学长的姿势之后发现中间那两条边没加反向边,但是据ATP说加了也没错,只是慢了一点。

应该就是两边都能流叭

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;

const int max_n=105;
const int max_m=105;
const int max_N=max_n*max_m+2;
const int max_M=max_N*10;
const int max_e=max_M;
const int INF=1e9;

int n,m,N,now,cnt,sum,maxflow;
int now1,now2,now3,now4;
int a[max_n][max_m],b[max_n][max_m],c[max_n][max_m],color[max_n][max_m];
int tot,point[max_N],next[max_e],v[max_e],remain[max_e];
int deep[max_N],cur[max_N];
queue <int> q;

inline void add(int x,int y,int cap){
++tot; next[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=cap;
}
inline void addedge(int x,int y,int cap){
sum+=cap;
add(x,y,cap);
add(y,x,0);
}
inline bool bfs(int s,int t){
memset(deep,0x7f,sizeof(deep));
deep[s]=0;
for (int i=1;i<=N;++i)
cur[i]=point[i];
while (!q.empty()) q.pop();
q.push(s);

while (!q.empty()){
int now=q.front(); q.pop();
for (int i=point[now];i!=-1;i=next[i])
if (deep[v[i]]>INF&&remain[i]){
deep[v[i]]=deep[now]+1;
q.push(v[i]);
}
}

return deep[t]<INF;
}
inline int dfs(int now,int t,int limit){
if (now==t||!limit) return limit;
int flow=0,f;
for (int i=cur[now];i!=-1;i=next[i]){
cur[now]=i;
if (deep[v[i]]==deep[now]+1&&(f=dfs(v[i],t,min(remain[i],limit)))){
flow+=f;
limit-=f;
remain[i]-=f;
remain[i^1]+=f;
if (!limit) break;
}
}
return flow;
}
inline void dinic(int s,int t){
while (bfs(s,t))
maxflow+=dfs(s,t,INF);
}

int main(){
tot=-1;
memset(point,-1,sizeof(point));
memset(next,-1,sizeof(next));

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]);
N=n*m+2;
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
if (i%2){
if (j%2) color[i][j]=1;
else color[i][j]=0;
}
else{
if (j%2) color[i][j]=0;
else color[i][j]=1;
}
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j){
now=(i-1)*m+j;
if (color[i][j]==1){
addedge(1,1+now,a[i][j]);
addedge(1+now,N,b[i][j]);
}
else{
addedge(1,1+now,b[i][j]);
addedge(1+now,N,a[i][j]);
}
if (!color[i][j]) continue;
if (i!=1) now1=now-m,add(1+now,1+now1,c[i][j]+c[i-1][j]),add(1+now1,1+now,c[i][j]+c[i-1][j]),sum+=c[i][j]+c[i-1][j];
if (i!=n) now2=now+m,add(1+now,1+now2,c[i][j]+c[i+1][j]),add(1+now2,1+now,c[i][j]+c[i+1][j]),sum+=c[i][j]+c[i+1][j];
if (j!=1) now3=now-1,add(1+now,1+now3,c[i][j]+c[i][j-1]),add(1+now3,1+now,c[i][j]+c[i][j-1]),sum+=c[i][j]+c[i][j-1];
if (j!=m) now4=now+1,add(1+now,1+now4,c[i][j]+c[i][j+1]),add(1+now4,1+now,c[i][j]+c[i][j+1]),sum+=c[i][j]+c[i][j+1];
}
dinic(1,N);
printf("%d\n",sum-maxflow);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: