• POJ2987 Firing


    嘟嘟嘟

    一道最小割的题。

    所有跟源点连边的点代表被解雇了,跟汇点连边的代表没被解雇。

    因为割掉每一条边代表付出一定的代价,所以应该先把正收益加起来,然后再减去最小割。

    那么对于所有解雇收益为正的点,从汇点连一条容量为该收益的边,割掉这条边代表不解雇这个人了,付出的代价就是这个收益;对于收益为负的点,向汇点连一条容量为该收益的绝对值的边,割掉他代表解雇这个人,付出的代价就是这个收益。

    如果y是x的上司,就从y向x连一条容量为INF的边,因为这个关系是无法改变的,所以改变他的代价是INF。

    最后跑网络流求最小割。(别忘开long long)

    对于第一问,我们只用在残图上跑一遍,能跑到的点就是解雇人数。因为所有和源点相连的代表被解雇了。

    很多题解都说是最大权闭合子图,建图也确实是这么建。然而我这觉得那么理解起来比较困难。

    还有一件事,这题我WA了n多发,然后跑残图的时候把e[i].cap > 0这个条件删了就莫名AC了……求助各路神仙。

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cmath>
      4 #include<algorithm>
      5 #include<cstring>
      6 #include<cstdlib>
      7 #include<cctype>
      8 #include<vector>
      9 #include<stack>
     10 #include<queue>
     11 using namespace std;
     12 #define enter puts("") 
     13 #define space putchar(' ')
     14 #define Mem(a, x) memset(a, x, sizeof(a))
     15 #define rg register
     16 typedef long long ll;
     17 typedef double db;
     18 const int INF = 0x3f3f3f3f;
     19 const db eps = 1e-8;
     20 const int maxn = 5e3 + 5;
     21 const int maxe = 2e6 + 5;
     22 inline ll read()
     23 {
     24     ll ans = 0;
     25     char ch = getchar(), last = ' ';
     26     while(!isdigit(ch)) {last = ch; ch = getchar();}
     27     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
     28     if(last == '-') ans = -ans;
     29     return ans;
     30 }
     31 inline void write(ll x)
     32 {
     33     if(x < 0) x = -x, putchar('-');
     34     if(x >= 10) write(x / 10);
     35     putchar(x % 10 + '0');
     36 }
     37 
     38 int n, m, t;
     39 ll sum = 0;
     40 
     41 struct Edge
     42 {
     43     int nxt, from, to;
     44     ll cap, flow;
     45 }e[maxe];
     46 int head[maxn], ecnt = -1;
     47 void addEdge(int x, int y, ll w)
     48 {
     49     e[++ecnt] = (Edge){head[x], x, y, w, 0};
     50     head[x] = ecnt;
     51     e[++ecnt] = (Edge){head[y], y, x, 0, 0}; 
     52     head[y] = ecnt;
     53 }
     54 
     55 int dis[maxn];
     56 bool bfs()
     57 {
     58     Mem(dis, 0); dis[0] = 1;
     59     queue<int> q; q.push(0);
     60     while(!q.empty())
     61     {
     62     int now = q.front(); q.pop();
     63     for(int i = head[now]; i != -1; i = e[i].nxt)
     64     {
     65         if(!dis[e[i].to] && e[i].cap > e[i].flow)
     66         {
     67         dis[e[i].to] = dis[now] + 1;
     68         q.push(e[i].to);
     69         }
     70     }
     71     }
     72     return dis[t];
     73 }
     74 int cur[maxn];
     75 ll dfs(int now, ll res)
     76 {
     77     if(now == t || res == 0) return res;                    
     78     ll flow = 0, f;
     79     for(int &i = cur[now]; i != -1; i = e[i].nxt)
     80     {
     81     if(dis[e[i].to] == dis[now] + 1 && (f = dfs(e[i].to, min(res, e[i].cap - e[i].flow))) > 0)
     82     {
     83         e[i].flow += f; e[i ^ 1].flow -= f;
     84         flow += f; res -= f;
     85         if(res == 0) break;
     86     }
     87     }
     88     return flow;
     89 }
     90 
     91 ll minCut()
     92 {
     93     ll flow = 0;
     94     while(bfs())
     95     {
     96       memcpy(cur, head, sizeof(head));  //这么写方便多了
     97       flow += dfs(0, (ll)INF * (ll)INF);
     98     }
     99     return flow;
    100 }
    101 
    102 int ans = 0;
    103 bool vis[maxn];
    104 void dfs2(int now)
    105 {
    106     vis[now] = 1; ans++;
    107     for(int i = head[now]; i != -1; i = e[i].nxt)
    108     {
    109       if(e[i].to != t && !vis[e[i].to] && e[i].cap > e[i].flow) 
    110     dfs2(e[i].to);
    111     }
    112 }
    113 
    114 int main()
    115 {
    116   Mem(head, -1);
    117     n = read(); m = read(); t = n + 1;
    118     for(int i = 1; i <= n; ++i)
    119     {
    120     int x = read();
    121     if(x > 0) addEdge(0, i, x), sum += x;
    122     else addEdge(i, t, -x);
    123     }
    124     for(int i = 1; i <= m; ++i)
    125     {
    126     int x = read(), y = read();
    127     addEdge(x, y, (ll)INF * (ll)INF);
    128     }
    129     ll x = minCut();
    130     dfs2(0);
    131     write(ans - 1), space; write(sum - x), enter;
    132     return 0;
    133 }
    View Code
  • 相关阅读:
    快速找到由程序员到CTO发展道路上的问路石
    从大师身上反思
    你真的了解企业虚拟化吗?
    “驱网核心技术丛书”创作团队访谈
    程序员到CTO需要准备什么
    深入搜索引擎的关键——索引
    程序员到CTO必须注意的几个关键点
    微软全球MVP教你如何规划程序人生
    “碟中碟”虚拟光驱软件开发者——万春 读《寒江独钓——Windows内核安全编程 》有感
    常用jar包之commonscollection使用
  • 原文地址:https://www.cnblogs.com/mrclr/p/9828917.html
Copyright © 2020-2023  润新知