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; }