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

BZOJ2127:happiness(最小割)

2018-03-12 10:05 375 查看
题面

题意:一群人,每人选文选里都有收益,相邻两个人同时选文和选理也有收益

问最大收益

二选一,应该是网络流

网络流忘得差不多了

我刚看到的时候什么都想不出

二选一能处理的问题

①两个人选不同的有代价

②一群人选相同某个的收益(一群人中的某人不选有代价)

属于S集则选文,否则选理

只考虑两个人A,B

套①,看似无法处理共同的问题

可以把共同选文的收益平分加在与S相连的边上

共同选理的收益加在与T相连的边上

算出代价为(共同选文的收益+共同选理的收益)/2

根据套路,直接在A,B间连双向边

套②,就很显然了

有一人选了理就无法获得共同选文的收益

在图上:有一人属于T集,则要割一条连接S与A,B的边

新建一个点与A,B连通,且与S有一条容量为共同选文收益的边

选理也一样



一丢丢总结

对于某个点(除了拆点),永远与S和T分别有边

且这两条割且只割一条,决定了它选什么

除了上面两个问题,其他都是最小割不可做的(同选有代价,异选有收益)

网络流边从2开始标号

网络流边从2开始标号

网络流边从2开始标号

#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))

typedef long long LL;

const int N=12345,M=2002000,oo=1e9+7;

int n,m,ans,T;
int wen[110][110],li[110][110],a[110][110];
int to[M],nex[M],cap[M],cnt=2;
int head
,lter
,level
,q
;

int p(int x,int y)
{
return (x-1)*m+y;
}
void add(int u,int v,int w,int rw)
{
to[cnt]=v;
cap[cnt]=w;
nex[cnt]=head[u];
head[u]=cnt++;
to[cnt]=u;
cap[cnt]=rw;
nex[cnt]=head[v];
head[v]=cnt++;
}

bool bfs()
{
q[1]=0;
mmcp(lter,head);
mmst(level,-1);
level[0]=1;
int hh=1,tt=1;
for(;hh<=tt;)
{
int hy=q[hh++];
for(int h=head[hy];h;h=nex[h])
if(cap[h]&&level[to[h]]<0)
{
q[++tt]=to[h];
level[to[h]]=level[hy]+1;
}
}
return level[T]>0;
}

int dfs(int v,int f)
{
if(v==T||!f)
return f;
int ret=0;
for(int &h=lter[v];h;h=nex[h])
if(cap[h]&&level[to[h]]>level[v])
{
int d=dfs(to[h],min(f,cap[h]));
ret+=d;
cap[h]-=d;
cap[h^1]+=d;
f-=d;
if(!f)
break;
}
return ret;
}

int main()
{
cin>>n>>m;
T=n*m+1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&wen[i][j]),wen[i][j]<<=1,ans+=wen[i][j];

for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&li[i][j]),li[i][j]<<=1,ans+=li[i][j];

for(int i=1;i<=n-1;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
ans+=a[i][j]+a[i][j];
wen[i][j]+=a[i][j];
wen[i+1][j]+=a[i][j];
}

for(int i=1;i<=n-1;i++)
for(int j=1;j<=m;j++)
{
int x;
scanf("%d",&x);
ans+=x+x;
add(p(i,j),p(i+1,j),a[i][j]+x,a[i][j]+x);
li[i][j]+=x;
li[i+1][j]+=x;
}

for(int i=1;i<=n;i++)
for(int j=1;j<=m-1;j++)
{
scanf("%d",&a[i][j]);
ans+=a[i][j]+a[i][j];
wen[i][j]+=a[i][j];
wen[i][j+1]+=a[i][j];
}

for(int i=1;i<=n;i++)
for(int j=1;j<=m-1;j++)
{
int x;
scanf("%d",&x);
ans+=x+x;
add(p(i,j),p(i,j+1),a[i][j]+x,a[i][j]+x);
li[i][j]+=x;
li[i][j+1]+=x;
}

for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
add(0,p(i,j),wen[i][j],0);
add(p(i,j),T,li[i][j],0);
}

int flow=0;
while(bfs())
ans-=dfs(0,oo);

cout<<ans/2<<endl;

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