【2011集训队出题】happiness

来源:互联网 发布:剑三叽太捏脸数据 编辑:程序博客网 时间:2024/05/16 11:05

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

这一题的建模比较有创意。
考虑建立一个超级源点S和一个超级汇点T。
从S连边到某个点表示选文科,从某个点连边到T表示选理科,边权值为给定的喜悦值。
对于两个点都选文的情况,就新建一个中间点,从S连到中间点,边权为喜悦值,再从中间点连向这两个点,边权设为inf。
类似的可以处理处理科的情况。
这里的连边很关键,也不是很好想。
代码还是比较好懂的。

Code

#include <cstdio>#include <algorithm>#include <cstring>#define P(x,y) (~-(x)*m+(y)) //快速算点坐标#define fo(i,a,b) for (i=a;i<=b;i++)using namespace std;const int maxn=500000;const int inf=10000007;int n,m,i,j,p,x,tot,ans,s,t,cnt;int next[maxn],head[maxn],b[maxn],c[maxn],d[maxn],q[maxn],cur[maxn];int read(){    int su=0;    char c=getchar();    while (c<'0'||c>'9') c=getchar();    while (c>='0'&&c<='9') {        su=su*10+c-'0';        c=getchar();    }    return su;}void plus(int x,int y,int z){ next[++tot]=head[x]; head[x]=tot; b[tot]=y; c[tot]=z;}void add(int x,int y,int z){ plus(x,y,z); plus(y,x,0);}int bfs(){    int l,r,x,i;    l=0,r=1; q[r]=s;    memset(d,0,sizeof(d));    d[s]=1;    while (l<r) {        x=q[++l];        for (i=head[x];i!=-1;i=next[i]){            if (c[i]!=0&&d[b[i]]==0) {                q[++r]=b[i];                d[b[i]]=d[x]+1;            }        }    }    if (d[t]>0) return 1;      else return 0;}   int dfs(int x,int f){    if (x==t) return f;    for (int & i=cur[x];i!=-1;i=next[i]){        if ((d[b[i]]==d[x]+1)&&(c[i]!=0)){            int di=dfs(b[i],min(c[i],f));               if   (di>0) {                  c[i]-=di;c[i^1]+=di;return di;}        }    }    return 0;}int main(){    n=read(),m=read();    tot=-1,cnt=n*m;    memset(head,-1,sizeof(head));    memset(next,-1,sizeof(next));    s=0; t=6*n*m+1;    int sum;     fo(i,1,n)      fo(j,1,m) {        x=read();        sum+=x;        p=P(i,j);        add(s,p,x);      }     fo(i,1,n)      fo(j,1,m) {         x=read();         sum+=x;         p=P(i,j);         add(p,t,x);          }    fo(i,1,n-1)      fo(j,1,m) {         x=read();         sum+=x;         p=P(i,j); cnt++;         add(s,cnt,x); add(cnt,p,inf); add(cnt,p+m,inf);      }      fo(i,1,n-1)        fo(j,1,m) {         x=read();         sum+=x;         p=P(i,j); cnt++;         add(cnt,t,x); add(p,cnt,inf);  add(p+m,cnt,inf);      }      fo(i,1,n)        fo(j,1,m-1) {            x=read();            sum+=x;            p=P(i,j); cnt++;            add(s,cnt,x); add(cnt,p,inf); add(cnt,p+1,inf);        }        fo(i,1,n)          fo(j,1,m-1){            x=read();            sum+=x;            p=P(i,j); cnt++;            add(cnt,t,x); add(p,cnt,inf); add(p+1,cnt,inf);          }    while (bfs()) {        fo(i,s,t) cur[i]=head[i];        while (int di=dfs(s,inf)) ans+=di;    }    printf("%d\n",sum-ans);}
原创粉丝点击