BZOJ 2039: [2009国家集训队]employ人员雇佣 最小割 二元组建图模型

来源:互联网 发布:cos后期特效软件 编辑:程序博客网 时间:2024/06/07 14:57

2039: [2009国家集训队]employ人员雇佣

Time Limit: 20 Sec  Memory Limit: 259 MB
Submit: 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
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集考虑,即取与不取,某人/点选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;}/*33 5 1000 6 16 0 21 2 01*/


转载分别来自

http://blog.csdn.NET/vmurder/article/details/42651751

http://www.cnblogs.com/chenyushuo/p/5146626.html

阅读全文
0 0