BZOJ 2127 : happiness 疯了的最小割
题目传送门
PS:幸好,先做了 阿狸和桃子的游戏 那一题,不然,想的脑壳teng。
【问题描述】
一群人选文理科,每人选文选里都有收益,相邻两个人同时选文和选理也有收益。
最大化收益。
【解题思路】
选文选理,二选一。
把所有的收益加起来,减去尽可能少的损失。
看起来像是网络流-最小割(其实就是)
参考bzoj2563阿狸和桃子的游戏
把边的权值,试图把边的权值分离在点上
就成了这样。。
两者不选文,则把文的都割掉。
两者不选理,则把理的都割掉。
那一边割理一边割文的怎么办?
那就再造一条val[文][AB]/2+val[理][AB]/2的边(图中双杠的边,把它也割掉)。反之亦然
最后成了这样。。
其实呢,这个图还是可以化简的(从黄学长那里看来的,简洁,cool~~~~~~~~~~)
完结,撒花~~~
【代码】
#include<bits/stdc++.h>
#define imax(a,b) ((a>b)?(a):(b))
#define imin(a,b) ((a<b)?(a):(b))
using namespace std;
typedef long long ll;
const int N=120;
const int M=300050;
int S,T,sum,n,m;
int P[N][N];
int ne[M],to[M],val[M],h[M],tt;
int d[N][N][2],g[N][N][2],s[N][N][2];
int q[M],bfstime;
int vis[M],lev[M];
void read(int &x)
{
x=0; char ch=getchar(); int f=1;
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
for(; isdigit(ch);ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
x*=f;
}
void addedge(int a,int b,int c)
{ to[++tt]=b; ne[tt]=h[a]; h[a]=tt; val[tt]=c; }
void addgo(int a,int b,int c)
{ addedge(a,b,c); addedge(b,a,0); }
bool bfs()
{
int head=1,tail=1;
q[head]=S;
vis[S]=++bfstime;
lev[S]=1;
while(head<=tail)
{
for(int p=h[q[head]];p;p=ne[p])
{
if(!val[p]) continue;
if(vis[to[p]]==bfstime) continue;
q[++tail]=to[p];
vis[to[p]]=bfstime;
lev[to[p]]=lev[q[head]]+1;
}
head++;
}
return vis[T]==bfstime;
}
int dfs(int now,int maxf)
{
int ret=0,t;
if(now==T || !maxf ) return maxf;
for(int p=h[now];p;p=ne[p])
{
if(!val[p] || lev[to[p]]!=lev[now]+1) continue;
t=dfs(to[p],imin(maxf,val[p]));
val[p]-=t;
val[p^1]+=t;
maxf-=t;
ret+=t;
}
if(maxf) lev[now]=-1;
return ret;
}
int dinic()
{
int ret=0;
while(bfs()) ret+=dfs(S,1e9);
return ret;
}
void init()
{
read(n); read(m); tt=1;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j) P[i][j]=(i-1)*m+j+1;
S=P[n][m]+1; T=S+1;
for(int o=0;o<2;o++)
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) read(d[i][j][o]),sum+=d[i][j][o],d[i][j][o]<<=1;
for(int o=0;o<2;o++)
for(int i=1;i<n;i++)
for(int j=1;j<=m;j++) read(g[i][j][o]),sum+=g[i][j][o];
for(int o=0;o<2;o++)
for(int i=1;i<=n;i++)
for(int j=1;j<m;j++) read(s[i][j][o]),sum+=s[i][j][o];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
addgo(S,P[i][j],d[i][j][0]+g[i][j][0]+g[i-1][j][0]+s[i][j][0]+s[i][j-1][0]);
addgo(P[i][j],T,d[i][j][1]+g[i][j][1]+g[i-1][j][1]+s[i][j][1]+s[i][j-1][1]);
if(i!=n)
{
addgo(P[i][j],P[i+1][j],g[i][j][0]+g[i][j][1]);
addgo(P[i+1][j],P[i][j],g[i][j][0]+g[i][j][1]);
}
if(j!=m)
{
addgo(P[i][j],P[i][j+1],s[i][j][0]+s[i][j][1]);
addgo(P[i][j+1],P[i][j],s[i][j][0]+s[i][j][1]);
}
}
}
int main()
{
init();
printf("%d\n",sum-(dinic()>>1));
return 0;
}