最大权闭合子图题目泛做

题目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\n", 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\n", tot - net.mx(S, T));
104   }
105   return 0;
106 }
3879

 

转载于:https://www.cnblogs.com/sxprovence/p/5348986.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值