【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 }
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
2127: happiness
Time Limit: 51 Sec Memory Limit: 259 MBSubmit: 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 1
100 110
1
1000
Sample Output
【样例说明】
两人都选理,则获得100+110+1000的喜悦值。
【数据规模】
对于100%以内的数据,n,m<=100 所有喜悦值均为小于等于5000的非负整数