2039: [2009国家集训队]employ人员雇佣
Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 1614 Solved: 789
[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 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
最小割心得:
首先需要一定的功底来发现这道题是最小割,并且投入思考。
然后想怎么建图:
最小割都是先算上所有收益,然后再通过网络图进行割边减去部分权值。
收益有时候可能带上负值。
然后我们需要思考什么能带来权值,什么会有权值冲突。
而最小割图一般都是拆成S集和T集考虑,即取与不取,某人/点选A或者选B等等,
这样就会带来冲突,也就是需要割的边。
然后我们需要把所有权值的得与失列出来,针对性建图,然后check几种情况:
比如两个人都在S集、都在T集,甲S乙T,甲T乙S等等,我们看这样会割掉哪些边,失去哪些权值。
如果发现建错了,也可以有针对性地进行修改。
提供一个较有普及型的最小割建图方法
回到这一道题
把自己和敌对公司看成机器A、B,把问题转换为最小花费
即可用最小割解决
那么不选一个点
就代表花费矩中的一行
选一个点就代表花费雇佣该经理的花费
在两个经理之间连E(i,j)<<1的边
代表两经理不在同一公司的增加花费
(<<1是因为两个经理不在同一公司会消耗E(i,j)两次,题意问题)
跑一遍最大流就OK啦
不知道为什么BJ的代码跑的如此之慢QWQ
转载分别来自 (当然 题解部分是BJ自己完成的)
http://blog.csdn.NET/vmurder/article/details/42651751
http://www.cnblogs.com/chenyushuo/p/5146626.html
#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<complex>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<map>
#include<set>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=10*x+ch-'0';ch=getchar();}
return x*f;
}
inline void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}
const int N=1010,M=3001000,inf=0X3f3f3f3f;
int ecnt=1,last[N];
struct EDGE{int to,nt,val;}e[M];
inline void readd(int u,int v,int val){e[++ecnt]=(EDGE){v,last[u],val};last[u]=ecnt;}
inline void add(int u,int v,int val){readd(u,v,val);readd(v,u,0);}
int n,S,T=N-1;
int q[N],d[N];
bool bfs()
{
memset(d,0,sizeof(d));d[0]=1;
int head=0,tail=1;q[0]=0;
while(head<tail)
{
int u=q[head++];head%=N;
for(int i=last[u];i;i=e[i].nt)
if(e[i].val&&!d[e[i].to])
{d[e[i].to]=d[u]+1;q[tail++]=e[i].to;tail%=N;}
}
return d[T];
}
int dfs(int u,int lim)
{
if(u==T||!lim)return lim;
int res=0;
for(int i=last[u];i;i=e[i].nt)
if(e[i].val&&d[e[i].to]==d[u]+1)
{
int tmp=dfs(e[i].to,min(lim,e[i].val));
lim-=tmp;e[i].val-=tmp;e[i^1].val+=tmp;res+=tmp;
if(!lim)break;
}
if(!res)d[u]=-1;
return res;
}
int ans;
void dinic(){while(bfs())ans+=dfs(S,inf);}
int main()
{
n=read();int sum=0;
for(int i=1,x;i<=n;++i){x=read();add(i,T,x);}
for(int i=1,tmp;i<=n;++i)
{
tmp=0;
for(int j=1,x;j<=n;++j)
{x=read();tmp+=x;if(i!=j)add(i,j,x<<1);}
sum+=tmp;add(S,i,tmp);
}
dinic();
print(sum-ans);
return 0;
}
/*
3
3 5 100
0 6 1
6 0 2
1 2 0
1
*/