2039: [2009国家集训队]employ人员雇佣
Time Limit: 20 Sec Memory Limit: 259 MB
Submit: 1791 Solved: 869
[Submit][Status][Discuss]
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
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部表示另一边。这种东西可以用来解决两两对立关系的选择。
答案一般为 sum-最小割,因为最小割表示的是一种损失最小的选择
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
#define ll long long
#define N 1005
using namespace std;
int n,m,tot,S,T,hd[N],d[N],cur[N],vis[N],cos[N],mp[N][N];ll sum[N],res;
struct edge{int v,next;ll cap;}e[N*N*4];
void adde(int u,int v,ll c){
e[tot].v=v;
e[tot].next=hd[u];
e[tot].cap=c;
hd[u]=tot++;
}
bool bfs(){
queue<int>q;
memset(vis,0,sizeof(vis));
d[S]=0;vis[S]=1;q.push(S);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=hd[u];~i;i=e[i].next){
int v=e[i].v;
if(e[i].cap&&!vis[v]){
vis[v]=1;
d[v]=d[u]+1;
q.push(v);
}
}
}
return vis[T];
}
ll dfs(int u,ll a){
if(u==T||!a)return a;
ll fl=0,f;
for(int &i=cur[u];~i;i=e[i].next){
int v=e[i].v;
if(e[i].cap&&d[v]==d[u]+1&&(f=dfs(v,min(e[i].cap,a)))){
fl+=f;a-=f;e[i].cap-=f;
e[i^1].cap+=f;if(!a)break;
}
}
return fl;
}
ll dinic(){
ll flow=0;
while(bfs()){
for(int i=S;i<=T;i++)cur[i]=hd[i];
flow+=dfs(S,inf);
}
return flow;
}
int main(){
#ifdef wsy
freopen("data.in","r",stdin);
#else
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
#endif
memset(hd,-1,sizeof(hd));
scanf("%d",&n);
S=0;T=n+1;
for(int i=1;i<=n;i++)scanf("%d",&cos[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
scanf("%d",&mp[i][j]);
sum[i]+=mp[i][j];
}
for(int i=1;i<=n;i++){
adde(S,i,sum[i]);
adde(i,S,0);
adde(i,T,cos[i]);
adde(T,i,0);
res+=sum[i];
}
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++){
adde(i,j,(ll)2*mp[i][j]);
adde(j,i,(ll)2*mp[i][j]);
}
ll flow=dinic();
printf("%lld",res-flow);
return 0;
}
来源:https://www.cnblogs.com/wsy01/p/7928182.html