標籤:.com 左右 mes turn 容量 getchar 直接 資料規模 畢業
題面戳我
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的非負整數
sol
首先把最大受益轉化成最小損失從而建立最小割模型。把每個矩陣中的每個數字都先加起來,然後用最小割求解最小損失。
下文中,我們用二元組\((p,q)\)來表示網路中從\(p\)連到\(q\)的邊的容量。
我們把選文科的劃在\(S\)這一邊,把選理科的劃在\(T\)這一邊。那麼這樣對一個單點\(x\)的處理就很簡單:直接令\((S,x)=\)選文科的收益,\((x,T)=\)選理科的收益即可。
但是兩人同時選文或選理的收益(或者說損失)要怎麼計算呢?
我們考慮兩個人\(x\),\(y\),他們倆一起選文的收益是\(u\),一起選理的收益是\(v\)。我們對於可能出現的\(2^2=4\)種情況分別討論。
1、\(x\),\(y\)都選文。此時被割掉的邊是\((x,T)\)和\((y,T)\),總損失應為\(v\);
2、\(x\),\(y\)都選理。此時被割掉的邊是\((S,x)\)和\((S,y)\),總損失應為\(u\);
3、\(x\)選文\(y\)選理。此時被割掉的邊是\((x,T)\)、\((S,y)\)和\((x,y)\),總損失應為\(u+v\);
4、\(x\)選理\(y\)選文。此時被割掉的邊是\((S,x)\)、\((y,T)\)和\((y,x)\),總損失應為\(u+v\)。
由上我們可以得到一個方程組:
\((x,T)+(y,T)=v\)
\((S,x)+(S,y)=u\)
\((x,T)+(S,y)+(x,y)=u+v\)
\((S,x)+(y,T)+(y,x)=u+v\)
(我太菜了實在是寫不出部落格園markdown的方程組。。。只能寫公式形式了)
只要是初中數學畢業了的就知道這個方程肯定解不出來(不定方程),但是考慮到這個東西並不會對其他產生影響,所以我們可以任意帶一組可行解進去。
令:
$(x,T) = v / 2 $
$(y,T) = v / 2 $
$(S,x) = u / 2 $
$(S,y) = u / 2 $
$(x,y) = (u + v) / 2 $
$(y,x) = (u + v) / 2 $
按照以上建圖方式即可。
由於除以二了以後可能會產生浮點數問題,所以考慮把所有邊擴大兩倍,保證所有容量是正整數。
code
#include<cstdio>#include<cstring>#include<algorithm>#include<queue>using namespace std;const int inf = 1e9;const int N = 110;struct edge{int to,next,w;}a[N*N<<3];int n,m,P[N][N],tot,v[6][N][N],S,T,head[N*N],cnt=1,dep[N*N],cur[N*N],sum;queue<int>Q;int gi(){ int x=0,w=1;char ch=getchar(); while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar(); if (ch=='-') w=0,ch=getchar(); while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x;}void link(int u,int v,int w,bool b){ a[++cnt]=(edge){v,head[u],w}; head[u]=cnt; a[++cnt]=(edge){u,head[v],b?w:0}; head[v]=cnt;}bool bfs(){ memset(dep,0,sizeof(dep)); dep[S]=1;Q.push(S); while (!Q.empty()) { int u=Q.front();Q.pop(); for (int e=head[u];e;e=a[e].next) if (a[e].w&&!dep[a[e].to]) dep[a[e].to]=dep[u]+1,Q.push(a[e].to); } return dep[T];}int dfs(int u,int flow){ if (u==T) return flow; for (int &e=cur[u];e;e=a[e].next) if (a[e].w&&dep[a[e].to]==dep[u]+1) { int temp=dfs(a[e].to,min(a[e].w,flow)); if (temp) {a[e].w-=temp;a[e^1].w+=temp;return temp;} } return 0;}int Dinic(){ int res=0; while (bfs()) { for (int i=T;i;i--) cur[i]=head[i]; while (int temp=dfs(S,inf)) res+=temp; } return res;}int main(){ n=gi();m=gi();S=n*m+1;T=n*m+2; for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) P[i][j]=++tot; for (int k=0;k<6;k++) { int x=n,y=m; if (k==2||k==3) x--; if (k==4||k==5) y--; for (int i=1;i<=x;i++) for (int j=1;j<=y;j++) v[k][i][j]=gi(),sum+=v[k][i][j]; } for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) { link(S,P[i][j],(v[0][i][j]<<1)+v[2][i][j]+v[2][i-1][j]+v[4][i][j]+v[4][i][j-1],0); link(P[i][j],T,(v[1][i][j]<<1)+v[3][i][j]+v[3][i-1][j]+v[5][i][j]+v[5][i][j-1],0); if (i<n) link(P[i][j],P[i+1][j],v[2][i][j]+v[3][i][j],1); if (j<m) link(P[i][j],P[i][j+1],v[4][i][j]+v[5][i][j],1); } printf("%d\n",sum-(Dinic()>>1)); return 0;}
[BZOJ2127]happiness