bzoj 2127: happiness

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

HINT

Source

为了博多的加强版。。。

首先这种划分成两个集合,然后满足一些条件会有收益求最优分配方案的题目

一般考虑总收益减去最小割,

理解起来就是本来这些收益全部可以获取,但要分为两个集合的话就是必须要舍弃一些边使得S,T不连通(分成两个集合),要舍弃的最少,就是最小割;

为了博多比较简单,只要在同一个集合中收益是相同的,但这个题略有不同;

具体的话2016年论文说得很好。。。

// MADE BY QT666
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#define RG register
using namespace std;
typedef long long ll;
const int N=1000050;
const int Inf=19260817;
const double eps=1e-5;
int gi(){
  int x=0,flag=1;
  char ch=getchar();
  while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
  while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
  return x*flag;
}
int head[N],to[N],nxt[N],level[N],S,T,q[N*10],cnt=1,n,m,tt;
double s[N],F;
int id[200][200],a[200][200],b[200][200],v1[200][200],v2[200][200],v3[200][200],v4[200][200];
int valt;
inline void Addedge(RG int x,RG int y,RG double z) {
  to[++cnt]=y,s[cnt]=z,nxt[cnt]=head[x],head[x]=cnt;
}
inline void lnk(RG int x,RG int y,RG double z){
  Addedge(x,y,z),Addedge(y,x,0);
}
inline bool bfs(){
  for(RG int i=S;i<=T;i++) level[i]=0;
  q[0]=S,level[S]=1;int t=0,sum=1;
  while(t<sum){
    int x=q[t++];
    if(x==T) return 1;
    for(RG int i=head[x];i;i=nxt[i]){
      int y=to[i];
      if(s[i]-0>=eps&&level[y]==0){
	level[y]=level[x]+1;
	q[sum++]=y;
      }
    }
  }
  return 0;
}
inline double dfs(RG int x,double maxf){
  if(x==T) return maxf;
  double ret=0;
  for(RG int i=head[x];i;i=nxt[i]){
    int y=to[i];double f=s[i];
    if(level[y]==level[x]+1&&f-0>=eps){
      double minn=min(f,maxf-ret);
      f=dfs(y,minn);
      s[i]-=f,s[i^1]+=f,ret+=f;
      if(ret==maxf) break;
    }
  }
  if(!ret) level[x]=0;
  return ret;
}
inline void Dinic(){
  while(bfs()) F+=dfs(S,Inf);
}
int main(){
  n=gi(),m=gi();S=0,T=n*m+1;
  for(RG int i=1;i<=n;i++)
    for(RG int j=1;j<=m;j++)
      id[i][j]=++tt;
  for(RG int i=1;i<=n;i++)
    for(RG int j=1;j<=m;j++)
      a[i][j]=gi(),lnk(S,id[i][j],a[i][j]),valt+=a[i][j];
  for(RG int i=1;i<=n;i++)
    for(RG int j=1;j<=m;j++)
      b[i][j]=gi(),lnk(id[i][j],T,b[i][j]),valt+=b[i][j];
  for(int i=1;i<=n-1;i++)
    for(RG int j=1;j<=m;j++)
      v1[i][j]=gi(),valt+=v1[i][j];
  for(RG int i=1;i<=n-1;i++)
    for(RG int j=1;j<=m;j++)
      v2[i][j]=gi(),valt+=v2[i][j];
  for(RG int i=1;i<=n-1;i++)
    for(RG int j=1;j<=m;j++){
      lnk(S,id[i][j],v1[i][j]/2.0);lnk(S,id[i+1][j],v1[i][j]/2.0);
      lnk(id[i][j],T,v2[i][j]/2.0);lnk(id[i+1][j],T,v2[i][j]/2.0);
      lnk(id[i][j],id[i+1][j],(v1[i][j]+v2[i][j])/2.0);
      lnk(id[i+1][j],id[i][j],(v1[i][j]+v2[i][j])/2.0);
    }
  for(RG int i=1;i<=n;i++)
    for(RG int j=1;j<=m-1;j++)
      v3[i][j]=gi(),valt+=v3[i][j];
  for(RG int i=1;i<=n;i++)
    for(RG int j=1;j<=m-1;j++)
      v4[i][j]=gi(),valt+=v4[i][j];
  for(RG int i=1;i<=n;i++)
    for(RG int j=1;j<=m-1;j++){
      lnk(S,id[i][j],v3[i][j]/2.0);lnk(S,id[i][j+1],v3[i][j]/2.0);
      lnk(id[i][j],T,v4[i][j]/2.0);lnk(id[i][j+1],T,v4[i][j]/2.0);
      lnk(id[i][j],id[i][j+1],(v3[i][j]+v4[i][j])/2.0);
      lnk(id[i][j+1],id[i][j],(v3[i][j]+v4[i][j])/2.0);
    }
  Dinic();printf("%d\n",valt-(int)F);
  return 0;
}

 

posted @ 2017-06-07 08:23  qt666  阅读(128)  评论(0编辑  收藏  举报