您的位置:首页 > 移动开发

BZOJ 2127 : happiness 疯了的最小割

2018-03-24 15:32 751 查看

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

;
int ne[M],to[M],val[M],h[M],tt;
int d

[2],g

[2],s

[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
[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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: