【最小割】BZOJ2039- [2009国家集训队]employ人员雇佣

【题目大意】

给定n个人,每个人有一个佣金,i和j如果同时被雇佣会产生2*E(i,j)的效益,i和j如果一个被雇佣一个不被雇佣会产生E(i,j)的亏损,求最大收益。

【思路】

如果没有亏损,其实非常类似这道题:

注意在这类问题里的最小割指代的是损失最小化。对于这道题,我们把S看作雇佣,T看作不雇佣。

首先对于每一个cost[i],从点i出发向汇点连一条流量为cost[i]的边。

对于每一对点(i,j),从S向点i和点j各连一条流量为E(i,j)的边,i和j之间连一条流量为2*E(i,j)的双向边。

ans最初等于矩阵里所有数的和。用ans减去最小割的时候,相当于割边没有被减去,而非割边被减去了。

如果割边是和S相连的,减去后,说明这个人雇佣了,付出了雇佣费,得到了一部分价值。

如果割边是和T相连的,减去后,说明没有雇佣,则没有付出雇佣费也没有得到价值。

那么对于一个被雇佣一个没有被雇佣呢?假设一个的割边与S连,一个的割边与Y连,那么必定会有中间的2*E(i,j)通过两者之间流走,所以他们之间的连边也必定成为割边。相当于得到了E[i,j]的价值,又丧失了2*E[i,j]的价值,总共丧失了E[i,j]的价值,符合题目意识。

dinic不知道为何写挂了,然后把程序里的函数一个一个拷贝到另一个空白界面重新编译了一下就过了,有毒quq没找到原来错在哪里。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<queue>
  6 #include<vector>
  7 #define S 0
  8 #define T n+1
  9 using namespace std;
 10 const int MAXN=1000+50;
 11 const int INF=0x7fffffff;
 12 struct node
 13 {
 14     int to,pos,cap;
 15 };
 16 int m,n,ans=0;
 17 vector<node> E[MAXN*3];
 18 int dis[MAXN],e[MAXN][MAXN],sum[MAXN];
 19
 20 void addedge(int u,int v,int w)
 21 {
 22     E[u].push_back((node){v,E[v].size(),w});
 23     E[v].push_back((node){u,E[u].size()-1,0});
 24 }
 25
 26 void init()
 27 {
 28     scanf("%d",&n);
 29     int cost;
 30     for (int i=1;i<=n;i++)
 31     {
 32         scanf("%d",&cost);
 33         addedge(i,T,cost);
 34     }
 35     int Eij;
 36     for (int i=1;i<=n;i++)
 37         for (int j=1;j<=n;j++)
 38         {
 39             scanf("%d",&e[i][j]);
 40             ans+=e[i][j];
 41             if (i!=j)
 42             {
 43                 sum[i]+=e[i][j];
 44                 addedge(i,j,2*e[i][j]);
 45             }
 46         }
 47     for (int i=1;i<=n;i++) addedge(S,i,sum[i]);
 48 }
 49
 50 bool bfs()
 51 {
 52     memset(dis,-1,sizeof(dis));
 53     queue<int> que;
 54     while (!que.empty()) que.pop();
 55     que.push(S);
 56     dis[S]=0;
 57     while (!que.empty())
 58     {
 59         int head=que.front();que.pop();
 60         if (head==T) return true;
 61         for (int i=0;i<E[head].size();i++)
 62         {
 63             node tmp=E[head][i];
 64             if (dis[tmp.to]==-1 && tmp.cap)
 65             {
 66                 dis[tmp.to]=dis[head]+1;
 67                 que.push(tmp.to);
 68             }
 69         }
 70     }
 71     return false;
 72 }
 73
 74 int dfs(int s,int e,int f)
 75 {
 76     if (s==e) return f;
 77     int ret=0;
 78     for (int i=0;i<E[s].size();i++)
 79     {
 80         node &tmp=E[s][i];
 81         if (dis[tmp.to]==dis[s]+1 && tmp.cap)
 82         {
 83             int delta=dfs(tmp.to,e,min(f,tmp.cap));
 84             if (delta>0)
 85             {
 86                 tmp.cap-=delta;
 87                 E[tmp.to][tmp.pos].cap+=delta;
 88                 f-=delta;
 89                 ret+=delta;
 90                 if (f==0) return ret;
 91             }
 92             else dis[tmp.to]=-1;
 93         }
 94     }
 95     return ret;
 96 }
 97
 98 void dinic()
 99 {
100     while (bfs())
101     {
102         int f=dfs(S,T,INF);
103         if (f) ans-=f;else break;
104     }
105     printf("%d\n",ans);
106 }
107
108 int main()
109 {
110     init();
111     dinic();
112     return 0;
113 }
时间: 2024-10-02 16:38:57

【最小割】BZOJ2039- [2009国家集训队]employ人员雇佣的相关文章

[Bzoj2039][2009国家集训队]employ人员雇佣(最小割)

2039: [2009国家集训队]employ人员雇佣 Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 1988  Solved: 951[Submit][Status][Discuss] Description 作为一个富有经营头脑的富翁,小L决定从本国最优秀的经理中雇佣一些来经营自己的公司.这些经理相互之间合作有一个贡献指数,(我们用Ei,j表示i经理对j经理的了解程度),即当经理i和经理j同时被雇佣时,经理i会对经理j做出贡献,使得所赚得的利

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

一开始就知道是最小割模型,然后开始乱搞建图,发现自己想错了... Orz PoPoQQQ,还给蒟蒻提供了很多帮助! 1 /************************************************************** 2 Problem: 2039 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time:5984 ms 7 Memory:64264 kb 8 *************************

【BZOJ 2039】 2039: [2009国家集训队]employ人员雇佣 (最小割)

2039: [2009国家集训队]employ人员雇佣 Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 1511  Solved: 728 Description 作为一个富有经营头脑的富翁,小L决定从本国最优秀的经理中雇佣一些来经营自己的公司.这些经理相互之间合作有一个贡献指数,(我们用Ei,j表示i经理对j经理的了解程度),即当经理i和经理j同时被雇佣时,经理i会对经理j做出贡献,使得所赚得的利润增加Ei,j.当然,雇佣每一个经理都需要花费一定

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

2039: [2009国家集训队]employ人员雇佣 Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 1369  Solved: 667[Submit][Status][Discuss] Description 作为一个富有经营头脑的富翁,小L决定从本国最优秀的经理中雇佣一些来经营自己的公司.这些经理相互之间合作有一个贡献指数,(我们用Ei,j表示i经理对j经理的了解程度),即当经理i和经理j同时被雇佣时,经理i会对经理j做出贡献,使得所赚得的利

BZOJ 2039 2009国家集训队 employ人员雇佣 最小割

题目大意:给定n个人,每个人有一个佣金,i和j如果同时被雇佣会产生2*E(i,j)的效益,i和j如果一个被雇佣一个不被雇佣会产生E(i,j)的亏损,求最大收益 首先对于每一个cost[i],从点i出发向汇点连一条流量为cost[i]的边 对于每一对点(i,j),建图如下: 从S向点i和点j各连一条流量为E(i,j)的边 i和j之间连一条流量为2*E(i,j)的双向边 这样可以保证每种割法对应一种雇佣方案 用矩阵上数字的总和减掉最小割即是答案 边集会很大,因此合并后再加即可 #include <c

BZOJ_2039_[2009国家集训队]employ人员雇佣_ 最小割

Description 作为一个富有经营头脑的富翁,小L决定从本国最优秀的经理中雇佣一些来经营自己的公司.这些经理相互之间合作有一个贡献指数,(我们用Ei,j表示i经理对j经理的了解程度),即当经理i和经理j同时被雇佣时,经理i会对经理j做出贡献,使得所赚得的利润增加Ei,j.当然,雇佣每一个经理都需要花费一定的金钱Ai,对于一些经理可能他做出的贡献不值得他的花费,那么作为一个聪明的人,小L当然不会雇佣他. 然而,那些没有被雇佣的人会被竞争对手所雇佣,这个时候那些人会对你雇佣的经理的工作造成影响

BZOJ 2039 [2009国家集训队]employ人员雇佣 网络流

链接 BZOJ 2039 题解 这题建图好神,自己瞎搞了半天,最后不得不求教了企鹅学长的博客,,,,发现建图太神了!! s向每个人连sum(e[i][x]) 的边,每个人向T连a[i]的边.两两人之间连2 * e[i][j]的边即可. 最后总的e – maxflow即为答案. 为什么我就没想到"源点向每个人连sum(e[i][x]) 的边"-- 犯的错误: 为了方便,对于双向边,用ADD(u, v, w), ADD(v, u, w)代替了ADD(u, v, w), ADD(v, u,

2009国家集训队 employ人员雇佣

Description 作为一个富有经营头脑的富翁,小L决定从本国最优秀的经理中雇佣一些来经营自己的公司.这些经理相互之间合作有一个贡献指数,(我们用Ei,j表示i经理对j经理的了解程度),即当经理i和经理j同时被雇佣时,经理i会对经理j做出贡献,使得所赚得的利润增加Ei,j.当然,雇佣每一个经理都需要花费一定的金钱Ai,对于一些经理可能他做出的贡献不值得他的花费,那么作为一个聪明的人,小L当然不会雇佣他. 然而,那些没有被雇佣的人会被竞争对手所雇佣,这个时候那些人会对你雇佣的经理的工作造成影响

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

任意门 Description 作为一个富有经营头脑的富翁,小L决定从本国最优秀的经理中雇佣一些来经营自己的公司.这些经理相互之间合作有一个贡献指数,(我们用Ei,j表示i经理对j经理的了解程度),即当经理i和经理j同时被雇佣时,经理i会对经理j做出贡献,使得所赚得的利润增加Ei,j.当然,雇佣每一个经理都需要花费一定的金钱Ai,对于一些经理可能他做出的贡献不值得他的花费,那么作为一个聪明的人,小L当然不会雇佣他. 然而,那些没有被雇佣的人会被竞争对手所雇佣,这个时候那些人会对你雇佣的经理的工作