【2011集训队出题】happiness

来源:互联网 发布:java 二分法排序代码 编辑:程序博客网 时间:2024/05/08 14:10

Description

  高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友。这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值。
  作为计算机竞赛教练的scp大老板,想知道如何分配可以使得全班的喜悦值总和最大。

Input

  第一行两个正整数n,m。
  接下来是六个矩阵
  第一个矩阵为n行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学选择文科获得的喜悦值。
  第二个矩阵为n行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学选择理科获得的喜悦值。
  第三个矩阵为n-1行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i+1行第j列的同学同时选择文科获得的额外喜悦值。
  第四个矩阵为n-1行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i+1行第j列的同学同时选择理科获得的额外喜悦值。
  第五个矩阵为n行m-1列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i行第j+1列的同学同时选择文科获得的额外喜悦值。
  第六个矩阵为n行m-1列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i行第j+1列的同学同时选择理科获得的额外喜悦值。

Output

输出一个整数,表示喜悦值总和的最大值

Sample Input

1 2
1 1
100 110
1
1000

Sample Output

1210

Hint

【样例说明】
  两人都选理,则获得100+110+1000的喜悦值。
【数据规模】
  对于10%以内的数据,n,m<=4
  对于30%以内的数据,n,m<=8
  对于100%以内的数据,n,m<=100 所有喜悦值均为小于等于5000的非负整数

Solution

同样是二元关系
感觉和圈地计划很像,但是这题的收益却不是同一个,而是不同的
这题就稍微推理一下
同样是取最大值,所以取反
两个人A,B
A文B文=-A文-B文-同文
A文B理=-A文-B文
A理B理=-A理-B理-同理
A理B文=-A理-B文
加上所有的收益(A文+B文+A理+B理+同文+同理)
变成
A文B文=A理+B理+同理
A文B理=A理+B文+同理+同文
A理B理=A文+B文+同文
A理B文=A文+B文+同理+同文
然后平分
已第一个为例
A文->A理+0.5*同理
B文->B理+0.5*同理
然后…………

最后的连边

源点向所有点连 文+0.5同文
所有点向汇点连 理+0.5同理
相邻的点(有关系的点) 连 0.5同文+0.5同理
这里的0.5同文或0.5同理都是对周围所有点的和
为了方便,可以先将所有点的权值*2变成整数,最后再/2
答案就是所有的和-最小割

Code

#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>#define fo(i,a,b) for(int i=a;i<=b;i++)#define no(x,y) ((x-1)*m+y)#define N 101using namespace std;int n,m,s,t,a[N][N],b[N][N],c[N][N],d[N][N],e[N][N],q[N][N],qu[555555],bz[555555],ans=0,next[555555],last[555555],to[555555],data[555555],tot=1;void putin(int x,int y,int z,int z1){    next[++tot]=last[x];last[x]=tot;to[tot]=y;data[tot]=z;    next[++tot]=last[y];last[y]=tot;to[tot]=x;data[tot]=z1;}bool bfs(){    int i=0,j=1;qu[1]=s;memset(bz,0,sizeof(bz));bz[s]=1;    while(i<j)    {        int l=qu[++i];        for(int k=last[l];k;k=next[k])            if(data[k]>0&&bz[to[k]]==0) bz[to[k]]=bz[l]+1,qu[++j]=to[k];    }    return bz[t]!=0;}int dfs(int x,int v){    if(x==t) return v;int ans=0;    for(int i=last[x];i;i=next[i])    {        int y=to[i];        if(bz[y]==bz[x]+1&&data[i]>0)        {            int qq=dfs(y,min(v,data[i]));            if(qq) data[i]-=qq,data[i^1]+=qq,ans+=qq,v-=qq;            if(v==0) return ans;        }    }    if(ans==0) bz[x]=-1;    return ans;}int main(){    scanf("%d%d",&n,&m);s=n*m+1;t=n*m+2;    fo(i,1,n) fo(j,1,m) scanf("%d",&a[i][j]),ans+=2*a[i][j];    fo(i,1,n) fo(j,1,m) scanf("%d",&b[i][j]),ans+=2*b[i][j];    fo(i,1,n-1) fo(j,1,m) scanf("%d",&c[i][j]),ans+=2*c[i][j];    fo(i,1,n-1) fo(j,1,m) scanf("%d",&d[i][j]),ans+=2*d[i][j];    fo(i,1,n) fo(j,1,m-1) scanf("%d",&e[i][j]),ans+=2*e[i][j];    fo(i,1,n) fo(j,1,m-1) scanf("%d",&q[i][j]),ans+=2*q[i][j];    fo(i,1,n) fo(j,1,m)    {        putin(s,no(i,j),2*a[i][j]+c[i][j]+c[i-1][j]+e[i][j]+e[i][j-1],0);        putin(no(i,j),t,2*b[i][j]+d[i][j]+d[i-1][j]+q[i][j]+q[i][j-1],0);        int x=i,y=j+1;        if(x<=n&&y<=m) putin(no(i,j),no(x,y),q[i][j]+e[i][j],q[i][j]+e[i][j]);        x=i+1,y=j;        if(x<=n&&y<=m) putin(no(i,j),no(x,y),c[i][j]+d[i][j],c[i][j]+d[i][j]);    }    while(bfs()) ans-=dfs(s,214748368);    printf("%d",ans/2);}
0 0
原创粉丝点击