最大权闭合子图题目泛做

题目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

时间: 2024-08-26 10:17:48

最大权闭合子图题目泛做的相关文章

NOI2006 最大获利(最大权闭合子图)

codevs 1789 最大获利 2006年NOI全国竞赛 时间限制: 2 s 空间限制: 128000 KB 题目描述 Description 新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是 挑战.THU 集团旗下的 CS&T 通讯公司在新一代通讯技术血战的前夜,需要做 太多的准备工作,仅就站址选择一项,就需要完成前期市场研究.站址勘测.最 优化等项目. 在前期市场调查和站址勘测之后,公司得到了一共 N 个可以作为通讯信号中 转站的地址,而由于这些地址的地理位置差异,在不同

hiho一下 第119周 #1398 : 网络流五&#183;最大权闭合子图 【最小割-最大流--Ford-Fulkerson 与 Dinic 算法】

#1398 : 网络流五·最大权闭合子图 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 周末,小Hi和小Ho所在的班级决定举行一些班级建设活动. 根据周内的调查结果,小Hi和小Ho一共列出了N项不同的活动(编号1..N),第i项活动能够产生a[i]的活跃值. 班级一共有M名学生(编号1..M),邀请编号为i的同学来参加班级建设活动需要消耗b[i]的活跃值. 每项活动都需要某些学生在场才能够进行,若其中有任意一个学生没有被邀请,这项活动就没有办法进行. 班级建设的活

1497: [NOI2006]最大获利(最大权闭合子图)

1497: [NOI2006]最大获利 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 5503  Solved: 2673 Description 新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战.THU集团旗下的CS&T通讯公司在新一代通讯技术血战的前夜,需要做太多的准备工作,仅就站址选择一项,就需要完成前期市场研究.站址勘测.最优化等项目.在前期市场调查和站址勘测之后,公司得到了一共N个可以作为通讯信号中转站的地址,而由于这

最大权闭合子图

所谓闭合子图就是给定一个有向图,从中选择一些点组成一个点集V.对于V中任意一个点,其后续节点都仍然在V中.比如: 在这个图中有8个闭合子图:?,{3},{4},{2,4},{3,4},{1,3,4},{2,3,4},{1,2,3,4} 小Ho:闭合子图我懂了,但是这跟我们这次的问题有啥关系呢? 小Hi:我们先把这次的问题转化为2分图.将N个活动看作A部,将M个学生看作B部.若第i个活动需要第j个学生,就连一条从A[i]到B[j]的有向边.比如对于例子: 假如选择A[1],则我们需要同时选择B[1

我和最大权闭合子图

第一次接触最大权闭合子图大概是2017年3月27号星期一,那段时间有5个同学(ZJC/LKQ/LWD/WJJ/...)去了湖南师大附中听PTY.BK他们讲课,因为我没有去Hfu一直很怪罪.后来安排我和LXY在70去电子科大之前去考一周的试,上午LXY的Mom接送,下午我们坐metro到世纪城再让LXY的Mom送回学校上晚自习.那一天我去70,T1是分治Floyd,T2是轮廓线DP,T3是一道最大权闭合子图(后来知道是BZOJ 3774 最优选择).那时我只会Dinic的模板,我的初高中学长Ana

1497. [NOI2006]最大获利【最大权闭合子图】

Description 新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战.THU集团旗下的CS&T通讯公司在新一代通讯技术血战的前夜,需要做太多的准备工作,仅就站址选择一项,就需要完成前期市场研究.站址勘测.最优化等项目.在前期市场调查和站址勘测之后,公司得到了一共N个可以作为通讯信号中转站的地址,而由于这些地址的地理位置差异,在不同的地方建造通讯中转站需要投入的成本也是不一样的,所幸在前期调查之后这些都是已知数据:建立第i个通讯中转站需要的成本为Pi(1≤i≤N).另外公

HDU5772 String problem(最大权闭合子图)

题目..说了很多东西 官方题解是这么说的: 首先将点分为3类 第一类:Pij 表示第i个点和第j个点组合的点,那么Pij的权值等于w[i][j]+w[j][i](表示得分) 第二类:原串中的n个点每个点拆出一个点,第i个点权值为 –a[s[i]] (表示要花费) 第三类:对于10种字符拆出10个点,每个点的权值为  -(b[x]-a[x]) 那么我们可以得到一个关系图 ,对于第一类中的点Pij,如果想要选择Pij,你就必须要选中第二类中的点i和j,对于第二类中的点如果你想选中第i个点,其对应的字

[BZOJ 1497][NOI 2006]最大获利(最大权闭合子图)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1497 分析: 这是在有向图中的问题,且边依赖于点,有向图中存在点.边之间的依赖关系可以考虑最大权闭合子图 假设a与b之间有权值为c的边(根据题意是双向边) 那么我们可以建一个新节点,点的权值为c,并指向a点和b点(单向),同时断掉原本a,b之间的双向边,a,b的点的权值是它们的花费(负的) 那么对于原问题就转化成了求最大权闭合子图的问题了 ——————————————————————

hdu 3996 Gold Mine 最大权闭合子图

Gold Mine Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2374    Accepted Submission(s): 514 Problem Description Long long ago, there is a gold mine.The mine consist of many layout, so some are