標籤:body cout ios png using turn 串連 方法 iostream
參考:https://www.cnblogs.com/chenyushuo/p/5144957.html 不得不說這個建圖方法真是非常妙啊
假設S點選理,T點選文,a[i][j]為(i,j)選文收益,b[i][j]為(i,j)選理收益,c[i][j]為同時選文收益,d[i][j]為同時選文收益。
那麼對於每個點x=(i+1)*m+j,我們串連
\[ c[s,x]=b[i][j] \]
\[ c[x,t]=a[i][j] \]
對於有利益相關的x,y兩點,串連
\[ c[s,x]=d[i][j]/2 \]
\[ c[s,y]=d[i][j]/2 \]
\[ c[x,t]=c[i][j]/2 \]
\[c[y,t]=c[i][j]/2 \]
\[ c[x,y]=c[i][j]/2+d[i][j]/2 \]
\[ c[y,x]=c[i][j]/2+d[i][j]/2 \]
建完的圖:
然後考慮最小割,下面枚舉幾種情況:
都選文,即割掉了x選理,y選理和(x,y)都選理:
都選理,即割掉了x選文,y選文和(x,y)都選文:
x選文y選理,即割掉了x選理,y選文,(x,y)都選理/+(x,y)都選理/2+(x,y)都選文/2+(x,y)都選文/2,即,割掉x選理,y選文,(x,y)都選理,(x,y)都選文:
y選文x選理,即割掉了x選文,y選理,(x,y)都選理/+(x,y)都選理/2+(x,y)都選文/2+(x,y)都選文/2,即,割掉x選文,y選理,(x,y)都選理,(x,y)都選文:
對於除以2的操作,為避免下取整的誤差,我們選擇把所有流量都*2,最後再/2。
$ ans=sum(全部收益)- 最小割 $
p.s.用鄰接表建圖的時候先把每個點選單科的邊連上,再練同時選的收益,否則會重
#include<iostream>#include<cstdio>#include<cstring>#include<queue>using namespace std;const int N=105,E=1000005,inf=1e9,P=500005;int n,m,a[N][N],b[N][N],c[N][N],d[N][N],s,t,sum,cnt=1,h[P],le[N*N];struct qwe{ int ne,to,va;}e[E];int read(){ int r=0; char p=getchar(); while(p<‘0‘||p>‘9‘) p=getchar(); while(p>=‘0‘&&p<=‘9‘) { r=r*10+p-48; p=getchar(); } return r;}void add(int u,int v,int w){ cnt++; e[cnt].ne=h[u]; e[cnt].to=v; e[cnt].va=w; h[u]=cnt;}bool bfs(){ queue<int>q; memset(le,0,sizeof(le)); le[s]=1; q.push(s); while(!q.empty()) { int u=q.front();//cout<<u<<"AAAAAAAAAAAA"<<endl; q.pop(); for(int i=h[u];i;i=e[i].ne) if(e[i].va&&!le[e[i].to]) { le[e[i].to]=le[u]+1; q.push(e[i].to); } } // for(int i=0;i<=5;i++) // cout<<le[i]<<" "; return le[t]; }int dfs(int u,int f){//cout<<u<<" "<<f<<endl; if(u==t) { //cout<<"!!"; return f; } int used=0; for(int i=h[u];i;i=e[i].ne) { //cout<<u<<" "<<e[i].to<<" "<<e[i].va<<endl;; if(e[i].va>0&&le[e[i].to]==le[u]+1) {//cout<<"OK"<<endl; int w=dfs(e[i].to,min(f-used,e[i].va)); e[i].va-=w; e[i^1].va+=w; used+=w; if(used==f) return f; } } if(!used) le[u]=-1; return used;}int dinic(){ int ans=0; while(bfs()) ans+=dfs(s,inf);//,cout<<ans<<endl; return ans;}int main(){ n=read(),m=read(); s=0,t=n*m+1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=read(),sum+=a[i][j]; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) b[i][j]=read(),sum+=b[i][j]; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { int x=(i-1)*m+j; add(s,x,b[i][j]<<1); add(x,s,0); add(x,t,a[i][j]<<1); add(t,x,0); } for(int i=1;i<n;i++) for(int j=1;j<=m;j++) c[i][j]=read(),sum+=c[i][j]; for(int i=1;i<n;i++) for(int j=1;j<=m;j++) d[i][j]=read(),sum+=d[i][j]; for(int i=1;i<n;i++) for(int j=1;j<=m;j++) { int x=(i-1)*m+j,y=i*m+j; add(s,x,d[i][j]); add(x,s,0); add(s,y,d[i][j]); add(y,s,0); add(x,y,c[i][j]+d[i][j]); add(y,x,c[i][j]+d[i][j]); add(x,t,c[i][j]); add(t,x,0); add(y,t,c[i][j]); add(t,y,0); } for(int i=1;i<=n;i++) for(int j=1;j<m;j++) c[i][j]=read(),sum+=c[i][j]; for(int i=1;i<=n;i++) for(int j=1;j<m;j++) d[i][j]=read(),sum+=d[i][j]; for(int i=1;i<=n;i++) for(int j=1;j<m;j++) { int x=(i-1)*m+j,y=(i-1)*m+j+1; add(s,x,d[i][j]); add(x,s,0); add(s,y,d[i][j]); add(y,s,0); add(x,y,c[i][j]+d[i][j]); add(y,x,c[i][j]+d[i][j]); add(x,t,c[i][j]); add(t,x,0); add(y,t,c[i][j]); add(t,y,0); } printf("%d\n",sum-(dinic()>>1)); return 0;}
bzoj 2127 happiness【網路流dinic】