题面
题意:一群人,每人选文选里都有收益,相邻两个人同时选文和选理也有收益
问最大收益
二选一,应该是网络流
网络流忘得差不多了
我刚看到的时候什么都想不出
二选一能处理的问题
①两个人选不同的有代价
②一群人选相同某个的收益(一群人中的某人不选有代价)
属于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[N],lter[N],level[N],q[N];
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;
}