[补档]happiness
happiness
题目
高一一班的座位表是个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 21 1100 11011000OUTPUT
1210
解题报告
选择不同时不能得到额外的权值,所以源点对所有点来说都是文科,汇点对所有点来说都是理科。
对于单独两个点来说,只有两种情况。
若两个人都选文科,需要割掉第2,4条边,代价为两个人选理科分别的贡献,以及他们一起选理科的贡献,因为所有的点都是等价的,2,4边的权值除各自选理科贡献外再加上一半的额外贡献。
若两个人都选择理科同理。
若两个人选择不同,假设x选择文科,y选择理科,那么需要割掉2,3,5。
此时2,3权值和为分别选择科目的贡献和一半的同时选择理科和同时选择文科的贡献。还需再减去剩余的一半,即应是5的权值。(x,y间要建双向边。)
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<queue> 5 using namespace std; 6 inline int read(){ 7 int sum(0); 8 char ch(getchar()); 9 for(;ch<'0'||ch>'9';ch=getchar()); 10 for(;ch>='0'&&ch<='9';sum=sum*10+(ch^48),ch=getchar()); 11 return sum; 12 } 13 struct edge{ 14 int e,n,w; 15 }a[200001]; 16 int pre[10010],tot; 17 inline void insert(int s,int e,int w){ 18 a[tot].e=e; 19 a[tot].w=w; 20 a[tot].n=pre[s]; 21 pre[s]=tot++; 22 } 23 int n,m; 24 int w[101][101],l[101][101]; 25 int jz1[101][101],jz2[101][101],jz3[101][101],jz4[101][101]; 26 int sum(0),ans(0),inf(0x7fffffff); 27 int S(0),T; 28 int id[101][101]; 29 inline void init(){ 30 freopen("nt2011_happiness.in","r",stdin); 31 freopen("nt2011_happiness.out","w",stdout); 32 memset(pre,-1,sizeof(pre)); 33 n=read(),m=read(); 34 T=n*m+1; 35 for(int i=1;i<=n;i++) 36 for(int j=1;j<=m;j++) 37 w[i][j]=read()<<1,sum+=w[i][j]>>1,id[i][j]=(i-1)*m+j; 38 for(int i=1;i<=n;i++) 39 for(int j=1;j<=m;j++) 40 l[i][j]=read()<<1,sum+=l[i][j]>>1; 41 for(int i=1;i<n;i++) 42 for(int j=1;j<=m;j++) 43 jz1[i][j]=read(),sum+=jz1[i][j]; 44 for(int i=1;i<n;i++) 45 for(int j=1;j<=m;j++) 46 jz2[i][j]=read(),sum+=jz2[i][j]; 47 for(int i=1;i<=n;i++) 48 for(int j=1;j<m;j++) 49 jz3[i][j]=read(),sum+=jz3[i][j]; 50 for(int i=1;i<=n;i++) 51 for(int j=1;j<m;j++) 52 jz4[i][j]=read(),sum+=jz4[i][j]; 53 } 54 inline void build(){ 55 for(int i=1;i<=n;i++) 56 for(int j=1;j<=m;j++){ 57 insert(S,id[i][j],w[i][j]+jz1[i][j]+jz1[i-1][j]+jz3[i][j]+jz3[i][j-1]),insert(id[i][j],S,0); 58 insert(id[i][j],T,l[i][j]+jz2[i][j]+jz2[i-1][j]+jz4[i][j]+jz4[i][j-1]),insert(T,id[i][j],0); 59 } 60 for(int i=1;i<=n;i++) 61 for(int j=1;j<=m;j++){ 62 if(i!=n) 63 insert(id[i][j],id[i][j]+m,jz1[i][j]+jz2[i][j]),insert(id[i][j]+m,id[i][j],jz1[i][j]+jz2[i][j]); 64 if(j!=m) 65 insert(id[i][j],id[i][j]+1,jz3[i][j]+jz4[i][j]),insert(id[i][j]+1,id[i][j],jz3[i][j]+jz4[i][j]); 66 } 67 } 68 int dis[10020]; 69 inline bool bfs(int s,int t){ 70 memset(dis,0,sizeof(dis)); 71 dis[s]=1; 72 queue<int>q; 73 q.push(s); 74 while(!q.empty()){ 75 int k(q.front()); 76 q.pop(); 77 for(int i=pre[k];i!=-1;i=a[i].n){ 78 int e(a[i].e); 79 if(!dis[e]&&a[i].w){ 80 dis[e]=dis[k]+1; 81 q.push(e); 82 if(e==t) 83 return true; 84 } 85 } 86 } 87 return false; 88 } 89 inline int my_min(int a,int b){ 90 return a<b?a:b; 91 } 92 inline int dfs(int now,int flow){ 93 if(now==T) 94 return flow; 95 int tmp(flow),f; 96 for(int i=pre[now];i!=-1;i=a[i].n){ 97 int e(a[i].e); 98 if(dis[e]==dis[now]+1&&tmp&&a[i].w){ 99 f=dfs(e,my_min(tmp,a[i].w)); 100 if(!f){ 101 dis[e]=0; 102 continue; 103 } 104 a[i].w-=f; 105 a[i^1].w+=f; 106 tmp-=f; 107 } 108 } 109 return flow-tmp; 110 } 111 inline void dinic(){ 112 while(bfs(S,T)) 113 ans+=dfs(S,inf); 114 printf("%d",sum-(ans>>1)); 115 } 116 inline int gg(){ 117 init(); 118 build(); 119 dinic(); 120 return 0; 121 } 122 int K(gg()); 123 int main(){;}