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
【数据规模和约定】
20%的数据中N<=10
50%的数据中N<=100
100%的数据中 N<=1000, Ei,j<=maxlongint, Ai<=maxlongint
Solution
网络流最小割。构图首先按照惯例,S向每个人连这个人所能造成的所有的价值(雇佣所有人的情况),每个人向T连雇佣他的花费。关键问题是如何处理经理相互影响的状况。当两个经理一个选一个不选的时候,我们不仅要割掉一个经理的价值和另一个经理的雇佣费用,还需要承受两个经理之间的影响后果。相当于我们不但不能获得E[i,j]的收益,还要倒扣E[i,j]的收益,相当于割掉一条边权为2*E[i,j]的边。所以我们这么构图:
然后跑一边最大流,用所有人都雇佣的最大收益减去最大流就得到答案。
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<climits>
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
}
typedef long long LL;
const int maxn=1010;
struct edge{
int to,next,same;
LL size;
}e[maxn*maxn*3];
const LL oo=LONG_LONG_MAX;
int E[maxn][maxn],n,a[maxn],num=0,head[maxn];
int que[maxn],dep[maxn],cur[maxn];
LL sum[maxn],ans=0;
void adde(int u,int v,LL w){
e[++num].to=v;e[num].size=w;
e[num].next=head[u];
head[u]=num;
}
void add(int u,int v,LL w){
adde(u,v,w);e[num].same=num+1;
adde(v,u,0);e[num].same=num-1;
}
bool bfs(){
memset(que,0,sizeof que);
memset(dep,0,sizeof dep);
int qhead=0,tail=1;
que[1]=0;dep[0]=1;
while(qhead<tail){
int now=que[++qhead];
for(int i=head[now];i;i=e[i].next){
if(!dep[e[i].to]&&e[i].size){
que[++tail]=e[i].to;
dep[e[i].to]=dep[now]+1;
if(e[i].to==n+1)return true;
}
}
}
return false;
}
LL dfs(int x,LL flow){
if(x==n+1||(!flow))return flow;
LL temp;
for(int &i=cur[x];i;i=e[i].next){
if(dep[e[i].to]==dep[x]+1&&(temp=dfs(e[i].to,min(flow,e[i].size)))){
e[i].size-=temp;
e[e[i].same].size+=temp;
return temp;
}
}
return 0;
}
void Dinic(){
while(bfs()){
int flow;
memcpy(cur,head,sizeof head);
while((flow=dfs(0,oo))){
ans-=flow;
}
}
}
int main(){
n=read();
for(int i=1;i<=n;i++){
a[i]=read();
add(i,n+1,a[i]);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
E[i][j]=read();
if(i!=j)add(i,j,E[i][j]<<1);
sum[i]+=E[i][j];
}
}
for(int i=1;i<=n;i++){
add(0,i,sum[i]);
ans+=sum[i];
}
Dinic();
printf("%lld\n",ans);
return 0;
}