BZOJ 2039人员雇佣

纵然是瞬间 提交于 2019-11-28 07:04:43

  这道题教会我一个道理靠谁也不如靠自己。

  当时学长已经讲了,然而一脸懵逼,好吧,上网搜题解,二脸懵逼,于是自己动手,丰衣足食。自己推!

  首先就是建模了,这道题谁与谁之间建模已经十分明了,超级源点,超级汇点没跑,重点在权值,首先,依照题意,是“舍弃”,因此基本确认为最小割,那么最小割从哪里割,就是我们每个人都雇佣所赚的钱(由样例可知,实际上是2倍所赚的钱,以下省略“*2”,简称合作金),但先不必算雇佣金,在一开始先只考虑赚钱,那么先说最简单的,两个人都雇佣,那么我们所赚的钱为两人合作金-雇佣两人所花的钱,那么我们割掉的边的流量就应当是雇佣金了,于是乎,连向终点的流量get,即为雇佣金。

  于是我们happy的继续推,如果这两个人我都不雇佣,那么我损失的就是雇佣他俩所赚的钱了,而我割的边的流量就是合作金,因为两人均摊,因此不必*2。

  最后,也就是个人认为比较复杂的就是一个雇佣一个不雇佣的情况,那么比起两人一起合作所产生的合作金我少的就是两倍合作金+敌对公司让我减少的一倍合作金+我所雇佣的那个人的雇佣金,由之前我们可知我割掉雇佣的那个人与汇点的时候已减少雇佣金,我割掉不雇佣的人与源点的时候以减去一倍合作金,于是乎,剩下的就是两倍合作金了,这就是两人之间的流量,记得开双向哈。

  总的来说就是这样,由简到难,由已知边的流量去推未知边的流量,找准总值为关键,实在不行就列个方程,怎样也能搞出来。

 

  1 #include<iostream>
  2 #include<cstdlib>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<queue>
  6 #include<algorithm>
  7 #include<cmath>
  8 using namespace std;
  9 int n,s,zz=1,t;
 10 long long co[1015],a[1015];
 11 struct ro{
 12     int to,from;
 13     int next;
 14     long long l;
 15 }road[9000000];
 16 void build(int x,int y,long long z){
 17     zz++;
 18     road[zz].l=z;
 19     road[zz].to=y;
 20     road[zz].from=x;
 21     road[zz].next=a[x];
 22     a[x]=zz;
 23     zz++;
 24     road[zz].to=x;
 25     road[zz].from=y;
 26     road[zz].next=a[y];
 27     road[zz].l=0;
 28     a[y]=zz;
 29 }
 30 long long sum[1005];
 31 long long deep[1005],cur[1015],cur2[1015];
 32 bool bfs(){
 33     memset(deep,0,sizeof(deep));
 34     queue<int> q1;
 35     q1.push(s);
 36     deep[s]=1;
 37     while(!q1.empty())
 38     {
 39         int x=q1.front();
 40         q1.pop();
 41         for(int i=a[x];i>0;i=road[i].next)
 42         {
 43             int y=road[i].to;
 44             if(road[i].l>0&&(!deep[y]))
 45             {
 46                 deep[y]=deep[x]+1;
 47                 q1.push(y);
 48             }
 49         }
 50     }
 51     if(!deep[t])return 0;
 52     return 1;
 53 }
 54 long long dfs(int x,long long sum){
 55     if(x==t||!sum) return sum;
 56     for(int i=cur[x];i>0;i=road[i].next)
 57     {
 58         cur[x]=i;
 59         int y=road[i].to;
 60         if(road[i].l>0&&deep[y]==deep[x]+1)
 61         {
 62             int k=dfs(y,min(sum,road[i].l));
 63             if(k)
 64             {
 65                 road[i].l-=k;
 66                 road[i^1].l+=k;
 67                 return k;
 68             }
 69         }
 70     }
 71     return 0;
 72 }
 73 long long work(){
 74     long long ans=0;
 75     memcpy(cur2,a,sizeof(a));
 76     while(bfs())
 77     {
 78         int x;
 79         memcpy(cur,cur2,sizeof(cur2));
 80         while(x=dfs(s,0x7fffffff))
 81         {
 82             ans+=x;
 83         }
 84     }
 85     return ans;
 86 }
 87 long long summ;
 88 int main(){
 89     scanf("%d",&n);
 90     t=n+1;
 91     for(int i=1;i<=n;i++)
 92     {
 93         scanf("%lld",&co[i]);
 94     }
 95     for(int i=1;i<=n;i++)
 96     {
 97         for(int j=1;j<=n;j++)
 98         {
 99             long long x;
100             scanf("%lld",&x);
101             if(x)build(i,j,x*2);
102             sum[i]+=x;
103         }
104     }
105     for(int i=1;i<=n;i++)
106     {
107         build(s,i,sum[i]);
108         build(i,t,co[i]);
109         summ+=sum[i];
110     }
111     printf("%lld\n",summ-work());
112     //while(1);
113     return 0;
114 }

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!