BZOJ_2039_[2009国家集训队]employ人员雇佣_ 最小割
BZOJ_2039_[2009国家集训队]employ人员雇佣_ 最小割
Description
作为一个富有经营头脑的富翁,小L决定从本国最优秀的经理中雇佣一些来经营自己的公司。这些经理相互之间合作有一个贡献指数,(我们用Ei,j表示i经理对j经理的了解程度),即当经理i和经理j同时被雇佣时,经理i会对经理j做出贡献,使得所赚得的利润增加Ei,j。当然,雇佣每一个经理都需要花费一定的金钱Ai,对于一些经理可能他做出的贡献不值得他的花费,那么作为一个聪明的人,小L当然不会雇佣他。 然而,那些没有被雇佣的人会被竞争对手所雇佣,这个时候那些人会对你雇佣的经理的工作造成影响,使得所赚得的利润减少Ei,j(注意:这里的Ei,j与上面的Ei,j 是同一个)。 作为一个效率优先的人,小L想雇佣一些人使得净利润最大。你可以帮助小L解决这个问题吗?
Input
第一行有一个整数N<=1000表示经理的个数 第二行有N个整数Ai表示雇佣每个经理需要花费的金钱 接下来的N行中一行包含N个数,表示Ei,j,即经理i对经理j的了解程度。(输入满足Ei,j=Ej,i)
Output
第一行包含一个整数,即所求出的最大值。
Sample Input
3 5 100
0 6 1
6 0 2
1 2 0
Sample Output
1
【数据规模和约定】
20%的数据中N<=10
50%的数据中N<=100
100%的数据中 N<=1000, Ei,j<=maxlongint, Ai<=maxlongint
转化为损失最少的最小割模型。
建立$S$,$T$分别表示选或不选,便于用$S$,$T$割集表示方案。
然后设两个经理$i$和$j$,连这样几条边$S->i(x1),S->j(x2),i->j(x3),i->T(x4),j->T(x5)$,括号内代表容量,$x$为设的未知数。
假设$i$和$j$都选,那么要割掉到$T$的两条边$x4+x5$。假设都不选,则需要割掉$S$连出的两条边$x1+x2$。
$i$选$j$不选,则需要割掉$x2+x3+x4$三条边。
然后分别和真正的收益对应一下,可以得到$x1=\sum\limits_{k=1}^{n}e[i][k]$ $x3=2*e[i][j]$ $x4=a[i]$。
于是建图跑最小割即可。
代码:
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; typedef long long ll; inline char nc() { static char buf[100000],*p1,*p2; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline int rd() { register int x=0; register char s=nc(); while(s<'0'||s>'9') s=nc(); while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+s-'0',s=nc(); return x; } #define N 1050 #define M 3000050 #define S (n+1) #define T (n+2) #define inf (1ll<<60) int n,a[N],e[N][N]; struct Dinic { int head[N],to[M],nxt[M],cnt; int dep[N],Q[N],l,r; ll flow[M],sum; inline void add(int u,int v,ll f) { to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; flow[cnt]=f; to[++cnt]=u; nxt[cnt]=head[v]; head[v]=cnt; flow[cnt]=0; } bool bfs() { memset(dep,0,sizeof(dep)); l=r=0; Q[r++]=S; dep[S]=1; while(l<r) { int x=Q[l++],i; for(i=head[x];i;i=nxt[i]) { if(!dep[to[i]]&&flow[i]) { dep[to[i]]=dep[x]+1; if(to[i]==T) return 1; Q[r++]=to[i]; } } } return 0; } ll dfs(int x,ll mf) { if(x==T) return mf; ll nf=0; int i; for(i=head[x];i;i=nxt[i]) { if(dep[to[i]]==dep[x]+1&&flow[i]) { ll tmp=dfs(to[i],min(mf-nf,flow[i])); if(!tmp) dep[to[i]]=0; nf+=tmp; flow[i]-=tmp; flow[i^1]+=tmp; if(nf==mf) break; } } return nf; } void dinic() { ll f; while(bfs()) while((f=dfs(S,inf))!=0) sum-=f; printf("%lld\n",sum); } }G; int main() { G.cnt=1; n=rd(); int i,j; for(i=1;i<=n;i++) a[i]=rd(); for(i=1;i<=n;i++) { ll now=0; for(j=1;j<=n;j++) { e[i][j]=rd(); G.sum+=e[i][j]; now+=e[i][j]; G.add(i,j,2*e[i][j]); } G.add(S,i,now); G.add(i,T,a[i]); } G.dinic(); }