bzoj2127: happiness

2127: happiness

Time Limit: 51 Sec  Memory Limit: 259 MB
Submit: 1665  Solved: 811
[Submit][Status][Discuss]

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的非负整数
 
仰慕一波....@Yuanziming
 
这题我的写法似乎非常奇怪?
看成最大权闭合子图
源点和汇点向点连边容量为收益
然后每次对于两个一起选择的情况 建立两个虚拟节点 分别表示选这两边的收益 向S和T连边 
然后虚拟点向集合中的点连边..
其实感觉说的挺乱的...具体还是看代码吧
这题和3438大概算是双倍经验...我就是按照那题的写法写的
 1 #include<bits/stdc++.h>
 2 #define N 50005
 3 #define inf 2147483647
 4 #define rep(i,l,r) for(int i=l;i<=r;i++)
 5 using namespace std;
 6 struct node{
 7     int to,next,w;
 8 }e[5000000];
 9 int head[N],m,n,x,y,ans,dis[N],T,tot=1,cnt,mp[4][110][110],a,num[110][110];
10 inline void ins(int u,int v,int w) {
11      e[++tot].to=v; e[tot].next=head[u]; head[u]=tot; e[tot].w=w;
12 }
13 inline void insert(int u,int v,int w) {
14      ins(u,v,w); ins(v,u,0);
15 }
16 inline bool bfs(){
17      memset(dis,-1,sizeof(dis)); queue<int>q; q.push(0); dis[0]=0;
18      while(!q.empty()) {
19           int x=q.front(); q.pop();
20           for(int k=head[x];k;k=e[k].next) 
21              if(dis[e[k].to]<0 && e[k].w>0) {
22                    dis[e[k].to]=dis[x]+1; q.push(e[k].to);
23              }
24      }
25      if(dis[T]>0) return 1;else return 0;
26 }
27 int find(int x,int low){
28      if(x==T) return low;
29      int delta=low,now;
30      for(int k=head[x];k;k=e[k].next) 
31        if(e[k].w>0 && dis[e[k].to]==dis[x]+1){ 
32            now=find(e[k].to,min(e[k].w,delta));
33            e[k].w-=now; e[k^1].w+=now;   delta-=now;
34            if(!delta) return low;
35         } 
36      dis[x]=-1;
37      return low-delta;
38 }
39 int main () {
40      scanf("%d%d",&n,&m); T=50001;
41      rep(i,1,n) rep(j,1,m) scanf("%d",&a),num[i][j]=++cnt,insert(0,num[i][j],a),ans+=a;
42      rep(i,1,n) rep(j,1,m) scanf("%d",&a),insert(num[i][j],T,a),ans+=a;
43      rep(i,1,n-1) rep(j,1,m) scanf("%d",&mp[0][i][j]);
44      rep(i,1,n-1) rep(j,1,m) scanf("%d",&mp[1][i][j]);
45      rep(i,1,n) rep(j,1,m-1) scanf("%d",&mp[2][i][j]); 
46      rep(i,1,n) rep(j,1,m-1) scanf("%d",&mp[3][i][j]);
47      rep(i,1,n-1) rep(j,1,m) {
48           x=++cnt; y=++cnt;
49           ans+=mp[0][i][j]+mp[1][i][j];
50           insert(x,num[i][j],inf); insert(x,num[i+1][j],inf);
51           insert(num[i][j],y,inf); insert(num[i+1][j],y,inf);
52           insert(0,x,mp[0][i][j]); insert(y,T,mp[1][i][j]);
53      }
54      rep(i,1,n) rep(j,1,m-1) {
55           x=++cnt; y=++cnt;
56           ans+=mp[2][i][j]+mp[3][i][j];
57           insert(x,num[i][j],inf); insert(x,num[i][j+1],inf);
58           insert(num[i][j],y,inf); insert(num[i][j+1],y,inf);
59           insert(0,x,mp[2][i][j]); insert(y,T,mp[3][i][j]);
60      }
61      while(bfs()) ans-=find(0,inf);
62      printf("%d",ans);
63 } 
View Code

 

posted @ 2016-09-19 19:33  Bloodline  阅读(106)  评论(0编辑  收藏  举报