1. 程式人生 > >bzoj 2039 [2009國家集訓隊]employ人員僱傭——二元關係

bzoj 2039 [2009國家集訓隊]employ人員僱傭——二元關係

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=2039

用最小割看。對於一組關係 i , j ,如果都選,收益 2*Ei,j,可以看作0,作為基準;如果一個選了一個沒選,不僅沒了 2*Ei,j,還會額外少E,所以是3*E;如果兩個都沒選,就是少了E;解一下的話, i 和 j 相互連邊的容量是 2*E ;源點連來的容量是0,連向匯點的容量是E。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace
std; const int N=1005,M=N*N<<1; const ll INF=3e12; int n,hd[N],xnt=1,cur[N],dfn[N];ll f[N]; int to[M],nxt[M];ll cap[M]; int q[N],he,tl; ll Mn(ll a,ll b){return a<b?a:b;} int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='
0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return fx?ret:-ret; } void add(int x,int y,ll z) { to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;cap[xnt]=z; to[++xnt]=x;nxt[xnt]=hd[y];hd[y]=xnt;cap[xnt]=0; } bool bfs() { memset(dfn,0,sizeof dfn);dfn[0]=1; q[he=tl=1]=0; while(he<=tl) {
int k=q[he++]; for(int i=hd[k],v;i;i=nxt[i]) if(!dfn[v=to[i]]&&cap[i]) dfn[v]=dfn[k]+1,q[++tl]=v; } return dfn[n+1]; } ll dinic(int cr,ll flow) { if(cr==n+1)return flow; ll use=0; for(int& i=cur[cr],v;i;i=nxt[i]) if(dfn[v=to[i]]==dfn[cr]+1&&cap[i]) { ll tmp=dinic(v,Mn(flow-use,cap[i])); if(!tmp)dfn[v]=0; use+=tmp;cap[i]-=tmp;cap[i^1]+=tmp; if(use==flow)return use; } return use; } int main() { n=rdn(); for(int i=1,d;i<=n;i++) d=rdn(),add(0,i,d); for(int i=1,d;i<=n;i++) for(int j=1;j<=n;j++) { d=rdn();if(i==j)continue; add(i,j,(ll)d<<1ll);f[i]+=d; } ll ans=0; for(int i=1;i<=n;i++)add(i,n+1,f[i]),ans+=f[i]; while(bfs())memcpy(cur,hd,sizeof hd),ans-=dinic(0,INF); printf("%lld\n",ans); return 0; }