• 最大权闭合子图题目泛做


    题目1 POJ2987

    题目大意:

    一个公司要裁员,每个成员都有自己的效益值,可正可负,而且每个人都有自己的直接下属,如果某个人被裁员,那么他的直接下属,他的下属的下属。。。。都会离开这家公司。

    现在请你确定裁员的方案,求最小裁员人数和公司的最大收益。

    算法讨论:

    选了一个点,其后继都必须要选,这是闭合子图的特点。所以这个题就是裸题啦。

    最小裁员人数就是与S相连的点数,公司的最大收益就是正权和-最小割。

    Code:

      1 #include <cstdlib>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #include <iostream>
      6 #include <queue>
      7 #include <vector>
      8 
      9 using namespace std;
     10 typedef long long ll;
     11 const int N = 50000 + 5;
     12 const ll oo = 10000000000000000LL;
     13 
     14 struct Edge {
     15   int from, to;
     16   ll cap, flow;
     17   Edge(int u = 0, int v = 0, ll cp = 0, ll fw = 0):
     18     from(u), to(v), cap(cp), flow(fw) {}
     19 };
     20 
     21 struct Dinic {
     22   int n, m, s, t;
     23   int cur[N], que[N * 10];
     24   ll dis[N];
     25   bool vis[N];
     26   vector <Edge> edges;
     27   vector <int> G[N];
     28 
     29   void add(int from, int to, ll cp) {
     30     edges.push_back(Edge(from, to, cp, 0));
     31     edges.push_back(Edge(to, from, 0, 0));
     32     m = edges.size();
     33     G[from].push_back(m - 2);
     34     G[to].push_back(m - 1);
     35   }
     36 
     37   bool bfs() {
     38     int head = 1, tail = 1;
     39     memset(vis, false, sizeof vis);
     40     dis[s] = 0; vis[s] = true; que[head] = s;
     41     while(head <= tail) {
     42       int x = que[head];
     43       for(int i = 0; i < (signed) G[x].size(); ++ i) {
     44         Edge &e = edges[G[x][i]];
     45         if(!vis[e.to] && e.cap > e.flow) {
     46           vis[e.to] = true;
     47           dis[e.to] = dis[x] + 1;
     48           que[++ tail] = e.to;
     49         }
     50       }
     51       ++ head;
     52     }
     53     return vis[t];
     54   }
     55 
     56   ll dfs(int x, ll a) {
     57     if(x == t || a == 0) return a;
     58     ll flw = 0, f;
     59     for(int &i = cur[x]; i < (signed) G[x].size(); ++ i) {
     60       Edge &e = edges[G[x][i]];
     61       if(dis[e.to] == dis[x] + 1 && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0) {
     62         e.flow += f; edges[G[x][i] ^ 1].flow -= f; a -= f; flw += f;
     63         if(a == 0) break;
     64       }
     65     }
     66     return flw;
     67   }
     68 
     69   ll mxflow(int s, int t) {
     70     this->s = s; this->t = t;
     71     ll flw = 0;
     72     while(bfs()) {
     73       memset(cur, 0, sizeof cur);
     74       flw += dfs(s, oo);
     75     }
     76     return flw;
     77   }
     78 
     79   int bfs(int s) {
     80     queue <int> q;
     81     memset(vis, false, sizeof vis);
     82     int cnt = 1;
     83     q.push(s); vis[s] = true;
     84     while(!q.empty()) {
     85       int x = q.front(); q.pop();
     86       for(int i = 0; i < (signed)G[x].size(); ++ i) {
     87         Edge e = edges[G[x][i]];
     88         if(!vis[e.to] && e.cap > e.flow) {
     89           vis[e.to] = true;
     90           ++ cnt;
     91           q.push(e.to);
     92         }
     93       }
     94     }
     95     return cnt - 1;
     96   }
     97 }net;
     98 
     99 int n, m, S, T, w[N];
    100 
    101 int main() {
    102   int ou = 0, as, bs;
    103   ll tot = 0, c = 0;
    104   scanf("%d%d", &n, &m);
    105   S = 0; T = n + 1;
    106   for(int i = 1; i <= n; ++ i) {
    107     scanf("%d", &w[i]);
    108     if(w[i] > 0) {
    109       net.add(S, i, w[i]);
    110       tot += w[i];
    111     }
    112     else if(w[i] < 0) {
    113       net.add(i, T, -w[i]);
    114     }
    115   }
    116   for(int i = 1; i <= m; ++ i) {
    117     scanf("%d%d", &as, &bs);
    118     net.add(as, bs, oo);
    119   }
    120   c = net.mxflow(S, T);
    121   tot = tot - c;
    122   ou = net.bfs(S);
    123   printf("%d %lld
    ", ou, tot);
    124   return 0;
    125 }
    2987

    题目2 HDU3879

    题目大意:

    要选择位置建立通信站,在第i个位置建立要花费的代价 为wi,如果i .. j两个点都建立了通信站,那么这两个点之间就可以进行通信,而且可以收获c的收益。

    求最大收益。

    算法讨论:

    我们把所有事情都看做一个事件,建立一个站是一个负权点,权值为wi,两个点都建立通信站是一个正权点,权值为c,而且这个点发生的前提是这两个点都已经建立了站点。

    所以满足闭合子图的定义,就这样直接建立网络流的模型即可。

    代码:

      1 #include <cstdlib>
      2 #include <cstdio>
      3 #include <iostream>
      4 #include <cstring>
      5 #include <algorithm>
      6 #include <vector>
      7 
      8 using namespace std;
      9 
     10 const int N = 55000 + 5;
     11 const int oo = 0x3f3f3f3f;
     12 
     13 struct Edge {
     14   int from, to, cap, flow;
     15   Edge(int u = 0, int v = 0, int cp = 0, int fw = 0) :
     16     from(u), to(v), cap(cp), flow(fw) {}
     17 };
     18 
     19 struct Dinic {
     20   int n, m, s, t;
     21   int dis[N], cur[N], que[N * 10];
     22   bool vis[N];
     23   vector <Edge> edges;
     24   vector <int> G[N];
     25 
     26   void clear() {
     27     for(int i = 0; i <= n; ++ i) G[i].clear();
     28     edges.clear();
     29     n = 0; s = t = 0;
     30   }
     31 
     32   void add(int from, int to, int cap) {
     33     edges.push_back(Edge(from, to, cap, 0));
     34     edges.push_back(Edge(to, from, 0, 0));
     35     m = edges.size();
     36     G[from].push_back(m - 2);
     37     G[to].push_back(m - 1);
     38   }
     39 
     40   bool bfs() {
     41     int head = 1, tail = 1;
     42     memset(vis, false, sizeof vis);
     43     dis[s] = 0; vis[s] = true; que[head] = s;
     44     while(head <= tail) {
     45       int x = que[head];
     46       for(int i = 0; i < (signed) G[x].size(); ++ i) {
     47         Edge &e = edges[G[x][i]];
     48         if(!vis[e.to] && e.cap > e.flow) {
     49           vis[e.to] = true;
     50           dis[e.to] = dis[x] + 1;
     51           que[++ tail] = e.to;
     52         }
     53       }
     54       ++ head;
     55     }
     56     return vis[t];
     57   }
     58 
     59   int dfs(int x, int a) {
     60     if(x == t || a == 0) return a;
     61     int flw = 0, f;
     62     for(int &i = cur[x]; i < (signed) G[x].size(); ++ i) {
     63       Edge &e = edges[G[x][i]];
     64       if(dis[e.to] == dis[x] + 1 && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0) {
     65         e.flow += f; edges[G[x][i] ^ 1].flow -= f; a -= f; flw += f;
     66         if(a == 0) break;
     67       }
     68     }
     69     return flw;
     70   }
     71 
     72   int mx(int s, int t) {
     73     this->s = s; this->t = t;
     74     int flw = 0;
     75     while(bfs()) {
     76       memset(cur, 0, sizeof cur);
     77       flw += dfs(s, oo);
     78     }
     79     return flw;
     80   }
     81 }net;
     82 
     83 int n, m, w[N];
     84 int S, T;
     85 
     86 int main() {
     87   int tot = 0, a, b, c;
     88   while(~scanf("%d%d", &n, &m)) {
     89     net.clear(); tot = 0;
     90     net.n = n + m + 1;
     91     S = 0; T = n + m + 1;
     92     for(int i = 1; i <= n; ++ i) {
     93       scanf("%d", &w[i]);
     94       net.add(i + m, T, w[i]);
     95     }
     96     for(int i = 1; i <= m; ++ i) {
     97       scanf("%d%d%d", &a, &b, &c);
     98       net.add(S, i, c);
     99       tot += c;
    100       net.add(i, a + m, oo);
    101       net.add(i, b + m, oo);
    102     }
    103     printf("%d
    ", tot - net.mx(S, T));
    104   }
    105   return 0;
    106 }
    3879
  • 相关阅读:
    TcpClient
    文字识别
    halcon17.12 win7 64深度学框架搭建
    halcon多个形状模板匹配
    halcon 瓶盖定位
    halcol9点标定
    一个机械臂的正逆解
    Matlab robot-9.10(rvctools) 建模与正逆解
    16路舵机控制器USB访问
    C#二维码识别
  • 原文地址:https://www.cnblogs.com/sxprovence/p/5348986.html
Copyright © 2020-2023  润新知