【BZOJ】【2127】happiness

网络流/最小割


  Orz Hzwer

  这题他题解说的比较简略……我手画了个图才明白过来……

  嗯对于每个人选文or理的单独收益大家应该很好理解……连S->i 权值为选文的喜悦值,i->T权值为选理的喜悦值,然后所有的加起来减去最小割即可。

  那么有了相邻的额外喜悦值怎么办呢?首先它跟之前的问题没有冲突,完全可以叠加来做。如上图考虑额外喜悦值,tot=w1+w2,那么我们能得到的最大喜悦值就是tot-最小割,如果我们是两个人选了相同的一科,那割掉的边必然是左边的两条(和为w1)或是右边的两条(和为w2),那如果是选了不同的两科,割掉的就是对角线上的三条边(和为w1+w2),显而易见,这样就可以利用【最小割】来求出最大的喜悦值了。

 

  这道题我遇到了一个神奇的情况……我跟Hzwer都是写的Dinic,但是我跑下来就有15000ms+,他的程序只有1400ms+,速度是我的十倍啊……

  后来我各种修改然后发现:我加了当前弧优化!这个题目中实际上每个点的边数并不多,所以当前弧优化并不明显,但是每次重建残量网络的时候都要重新初始化一遍当前弧数组cur,这带来了大量的时间浪费……所以就华丽丽地……还好没超时。

  所以对于稀疏图还是不要用当前弧优化了= =尤其是在增广次数比较多的时候……

  1 /**************************************************************
  2     Problem: 2127
  3     User: Tunix
  4     Language: C++
  5     Result: Accepted
  6     Time:15184 ms
  7     Memory:6232 kb
  8 ****************************************************************/
  9  
 10 //BZOJ 2127
 11 #include<vector>
 12 #include<cstdio>
 13 #include<cstring>
 14 #include<cstdlib>
 15 #include<iostream>
 16 #include<algorithm>
 17 #define rep(i,n) for(int i=0;i<n;++i)
 18 #define F(i,j,n) for(int i=j;i<=n;++i)
 19 #define D(i,j,n) for(int i=j;i>=n;--i)
 20 #define pb push_back
 21 using namespace std;
 22 inline int getint(){
 23     int v=0,sign=1; char ch=getchar();
 24     while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
 25     while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
 26     return v*sign;
 27 }
 28 const int N=11000,M=300000,INF=~0u>>2;
 29 typedef long long LL;
 30 /******************tamplate*********************/
 31 int n,m,ans,tot,a[110][110],b[110][110];
 32 struct edge{
 33     int from,to,v;
 34 };
 35 inline int pack(int i,int j){return (i-1)*m+j;}
 36 struct Net{
 37     edge E[M];
 38     int head[N],next[M],cnt;
 39     void add(int x,int y,int v){
 40         E[++cnt]=(edge){x,y,v};
 41         next[cnt]=head[x]; head[x]=cnt;
 42         E[++cnt]=(edge){y,x,0};
 43         next[cnt]=head[y]; head[y]=cnt;
 44     }
 45     void add2(int x,int y,int v){
 46         E[++cnt]=(edge){x,y,v};
 47         next[cnt]=head[x]; head[x]=cnt;
 48         E[++cnt]=(edge){y,x,v};
 49         next[cnt]=head[y]; head[y]=cnt;
 50     }
 51     int s,t,cur[N],d[N],Q[N];
 52     void init(){
 53         n=getint();m=getint();
 54         ans=tot=0;cnt=1;
 55         s=0; t=n*m+1;
 56         F(i,1,n) F(j,1,m){
 57             a[i][j]=getint();
 58             tot+=a[i][j]; a[i][j]<<=1;
 59         }
 60         F(i,1,n) F(j,1,m){
 61             b[i][j]=getint();
 62             tot+=b[i][j]; b[i][j]<<=1;
 63         }
 64         int x;
 65         F(i,1,n-1) F(j,1,m){
 66             x=getint(); tot+=x;
 67             a[i][j]+=x; a[i+1][j]+=x;
 68             add2(pack(i,j),pack(i+1,j),x);
 69         }
 70         F(i,1,n-1) F(j,1,m){
 71             x=getint(); tot+=x;
 72             b[i][j]+=x; b[i+1][j]+=x;
 73             add2(pack(i,j),pack(i+1,j),x);
 74         }
 75         F(i,1,n) F(j,1,m-1){
 76             x=getint(); tot+=x;
 77             a[i][j]+=x; a[i][j+1]+=x;
 78             add2(pack(i,j),pack(i,j+1),x);
 79         }
 80         F(i,1,n) F(j,1,m-1){
 81             x=getint(); tot+=x;
 82             b[i][j]+=x; b[i][j+1]+=x;
 83             add2(pack(i,j),pack(i,j+1),x);
 84         }
 85         F(i,1,n) F(j,1,m){
 86             add(s,pack(i,j),a[i][j]);
 87             add(pack(i,j),t,b[i][j]);
 88         }
 89     }
 90     bool mklevel(){
 91         memset(d,-1,sizeof d);
 92         d[s]=0;
 93         int l=0,r=-1;
 94         Q[++r]=s;
 95         while(l<=r){
 96             int x=Q[l++];
 97             for(int i=head[x];i;i=next[i])
 98                 if (d[E[i].to]==-1 && E[i].v){
 99                     d[E[i].to]=d[x]+1;
100                     Q[++r]=E[i].to;
101                 }
102         }
103         return d[t]!=-1;
104     }
105     int dfs(int x,int a){
106         if (x==t||a==0) return a;
107         int flow=0;
108         for(int &i=cur[x];i && flow<a;i=next[i])
109             if (d[E[i].to]==d[x]+1 && E[i].v){
110                 int f=dfs(E[i].to,min(a-flow,E[i].v));
111                 E[i].v-=f;
112                 E[i^1].v+=f;
113                 flow+=f;
114             }
115         return flow;
116     }
117     int Dinic(){
118         int flow=0;
119         while(mklevel()){
120             F(i,s,t) cur[i]=head[i];
121             flow+=dfs(s,INF);
122         }
123         return flow;
124     }
125 }G1;
126 int main(){
127 #ifndef ONLINE_JUDGE
128     freopen("2127.in","r",stdin);
129     freopen("2127.out","w",stdout);
130 #endif
131     G1.init();
132     printf("%d\n",tot-(G1.Dinic()>>1));
133     return 0;
134 }
View Code 时间超长……
  1 /**************************************************************
  2     Problem: 2127
  3     User: Tunix
  4     Language: C++
  5     Result: Accepted
  6     Time:1332 ms
  7     Memory:4600 kb
  8 ****************************************************************/
  9  
 10 //BZOJ 2127
 11 #include<cstdio>
 12 #include<cstring>
 13 #include<algorithm>
 14 #define rep(n,m) for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
 15 #define FOR for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
 16 using namespace std;
 17 inline int getint(){
 18     int v=0,sign=1; char ch=getchar();
 19     while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
 20     while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
 21     return v*sign;
 22 }
 23 const int N=10005,M=300000,INF=~0u>>2;
 24 typedef long long LL;
 25 /******************tamplate*********************/
 26 int n,m,ans,tot,a[101][101],b[101][101],pack[101][101];
 27 struct edge{
 28     int to,v;
 29 };
 30 edge E[M];
 31 int head[N],next[M],cnt;
 32 void ins(int x,int y,int v){
 33     ++cnt; E[cnt].to=y; E[cnt].v=v;
 34     next[cnt]=head[x]; head[x]=cnt;
 35 }
 36 void add(int x,int y,int v){
 37     ins(x,y,v); ins(y,x,0);
 38 }
 39 void add2(int x,int y,int v){
 40     ins(x,y,v); ins(y,x,v);
 41 }
 42 int s,t,cur[N],d[N],Q[N];
 43 void init(){
 44     n=getint();m=getint();
 45     ans=tot=0;cnt=1;
 46     s=0; t=n*m+1;
 47     FOR a[i][j]=getint(),tot+=a[i][j],a[i][j]<<=1;
 48     FOR b[i][j]=getint(),tot+=b[i][j],b[i][j]<<=1;
 49     FOR pack[i][j]=(i-1)*m+j;
 50     int x;
 51     rep(n-1,m){
 52         x=getint(); tot+=x;
 53         a[i][j]+=x; a[i+1][j]+=x;
 54         add2(pack[i][j],pack[i+1][j],x);
 55     }
 56     rep(n-1,m){
 57         x=getint(); tot+=x;
 58         b[i][j]+=x; b[i+1][j]+=x;
 59         add2(pack[i][j],pack[i+1][j],x);
 60     }
 61     rep(n,m-1){
 62         x=getint(); tot+=x;
 63         a[i][j]+=x; a[i][j+1]+=x;
 64         add2(pack[i][j],pack[i][j+1],x);
 65     }
 66     rep(n,m-1){
 67         x=getint(); tot+=x;
 68         b[i][j]+=x; b[i][j+1]+=x;
 69         add2(pack[i][j],pack[i][j+1],x);
 70     }
 71     FOR{
 72         add(s,pack[i][j],a[i][j]);
 73         add(pack[i][j],t,b[i][j]);
 74     }
 75 }
 76 bool mklevel(){
 77     memset(d,-1,sizeof d);
 78     d[s]=0;
 79     int l=0,r=-1;
 80     Q[++r]=s;
 81     while(l<=r){
 82         int x=Q[l++];
 83         for(int i=head[x];i;i=next[i])
 84             if (d[E[i].to]==-1 && E[i].v){
 85                 d[E[i].to]=d[x]+1;
 86                 Q[++r]=E[i].to;
 87             }
 88     }
 89     return d[t]!=-1;
 90 }
 91 int dfs(int x,int a){
 92     if (x==t||a==0) return a;
 93     int flow=0;
 94     for(int i=head[x];i && flow<a;i=next[i])
 95         if (d[E[i].to]==d[x]+1 && E[i].v){
 96             int f=dfs(E[i].to,min(a-flow,E[i].v));
 97             E[i].v-=f;
 98             E[i^1].v+=f;
 99             flow+=f;
100         }
101     if (!flow) d[x]=-1;
102     return flow;
103 }
104 void Dinic(){
105     while(mklevel()) ans+=dfs(s,INF);
106 }
107 int main(){
108 #ifndef ONLINE_JUDGE
109     freopen("2127.in","r",stdin);
110     freopen("2127.out","w",stdout);
111 #endif
112     init(); Dinic();
113     printf("%d\n",tot-(ans>>1));
114     return 0;
115 }
116 
View Code 速度超快~

 

2127: happiness

Time Limit: 51 Sec  Memory Limit: 259 MB
Submit: 923  Solved: 444
[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的非负整数

HINT

Source

[Submit][Status][Discuss]
posted @ 2015-03-14 18:36  Tunix  阅读(290)  评论(0编辑  收藏  举报