bzoj2039
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; }
If you live in the echo,
your heart never beats as loud.
如果你生活在回声里,
你的心跳声永远不会轰鸣作响。