题意:
给出一个nxm的座位表,每个同学学文或学理有一个喜悦度;
并且如果两个挨着的同学一起学文或学理,会再有一个喜悦度加成;
喜悦度都为非负整数,n,m<=100,答案在int内;
题解:
文理分科,似乎是网络流的经典问题呢;
因为让所有人都幸福的世界是不可能存在的,所以我们就采用最小割的思想;
先将所有的喜悦度都加起来,然后将割掉一些使其合法,当然要满足割最小;
这里的建图还是去膜了黄学长,然后得到建图如下;
黄学长的建图非常有道理,具体来说就是这样的一个图 (我们暂且考虑两个点):对于原图中所有相邻的两个人A,B,我们建边:
s->A:cost[A文]+c[文][A][B]/2,s->B:cost[B文]+c[文][A][B]/2;
A->t:cost[A理]+c[理][A][B]/2,B->t:costB[理]+c[理][A][B]/2;
A<–>B:c[文][A][B]/2+c[理][A][B]/2
建图之后,显然这个网络只有这四种割是可能最小的;
而这又恰好代表了四种不同的方案,引申到更多点也是同理的;
所以得到原图的最小割之后,用总的喜悦度减去就可以了;
为了避免精度误差将所有喜悦度翻倍之后再计算;
注意那个双向边要建真正的双向而不是两条单向,因为两条单向的复杂度会变得很奇怪。。。
代码:
#include<queue>
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 110
#define M 1210000
using namespace std;
int c[6][N][N],num[N][N];
int next[M],to[M],flow[M],head[N*N],ce=1;
int S,T,dis[N*N];
queue<int>q;
void add(int x,int y,int fl)
{
if(!x||!y) return ;
to[++ce]=y;
flow[ce]=fl;
next[ce]=head[x];
head[x]=ce;
to[++ce]=x;
flow[ce]=0;
next[ce]=head[y];
head[y]=ce;
}
void add2(int x,int y,int fl)
{
if(!x||!y) return ;
to[++ce]=y;
flow[ce]=fl;
next[ce]=head[x];
head[x]=ce;
to[++ce]=x;
flow[ce]=fl;
next[ce]=head[y];
head[y]=ce;
}
bool BFS()
{
memset(dis,0,sizeof(dis));
dis[S]=1;
q.push(S);
int i,x;
while(!q.empty())
{
x=q.front(),q.pop();
for(i=head[x];i;i=next[i])
{
if(flow[i]&&!dis[to[i]])
{
dis[to[i]]=dis[x]+1;
q.push(to[i]);
}
}
}
return dis[T]!=0;
}
int dfs(int x,int fl)
{
if(x==T) return fl;
int i,ret,temp;
for(i=head[x],ret=0;i;i=next[i])
{
if(flow[i]&&dis[to[i]]==dis[x]+1)
{
temp=dfs(to[i],min(fl-ret,flow[i]));
ret+=temp;
flow[i]-=temp,flow[i^1]+=temp;
if(ret==fl)
return ret;
}
}
return ret;
}
int main()
{
int n,m,i,j,k,x,y,ans,sum;
scanf("%d%d",&n,&m);
sum=0;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&c[0][i][j]),sum+=c[0][i][j];
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&c[1][i][j]),sum+=c[1][i][j];
for(i=1;i<n;i++)
for(j=1;j<=m;j++)
scanf("%d",&c[2][i][j]),sum+=c[2][i][j];
for(i=1;i<n;i++)
for(j=1;j<=m;j++)
scanf("%d",&c[3][i][j]),sum+=c[3][i][j];
for(i=1;i<=n;i++)
for(j=1;j<m;j++)
scanf("%d",&c[4][i][j]),sum+=c[4][i][j];
for(i=1;i<=n;i++)
for(j=1;j<m;j++)
scanf("%d",&c[5][i][j]),sum+=c[5][i][j];
for(i=1,k=0;i<=n;i++)
for(j=1;j<=m;j++)
num[i][j]=++k;
S=++k,T=++k,sum<<=1;
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
x=num[i][j];
add(S,x,(c[0][i][j]<<1)+c[2][i-1][j]+c[2][i][j]+c[4][i][j-1]+c[4][i][j]);
add(x,T,(c[1][i][j]<<1)+c[3][i-1][j]+c[3][i][j]+c[5][i][j-1]+c[5][i][j]);
add2(x,num[i+1][j],c[2][i][j]+c[3][i][j]);
add2(x,num[i][j+1],c[4][i][j]+c[5][i][j]);
}
}
ans=0;
while(BFS())
ans+=dfs(S,0x3f3f3f3f);
sum-=ans;
sum>>=1;
printf("%d\n",sum);
return 0;
}