POJ 3155 最大密度子图

链接:

http://poj.org/problem?id=3155

题解:

要最大化下式:

可以用二分求解以下分数规划问题:

也就是最大化:

设子图为G‘=(V‘, E‘)。如果边(u,v)∈E‘,那么必有u,v属于V‘。把点权设为负值的话,问题可以转换为求最大权闭合图(POJ 2987 Firing)。

又因为点固定时,边越多越好。所以转换思路,不是边E‘决定点集V‘,而应该反过来。当选定点集V‘后,V‘内部两两之间能构成的边就是最佳的E‘。那么由V‘发出的,不在E‘内部的那些边构成了一个割集,当此割集最小时,E‘最大。问题归结于求解最小割。

上图g为答案的猜测值,d为度数(出度+入度),c为割集(V‘和V‘补集构成的边)。

此时构图方式:

即是将原图 G(E) 转化为网络 = (VE) 的过程:在原图点集的基础上增加源 和汇 ;将每条原无向边 (u,v) 替换为两条容量为1的有向边uv  v,u  ;增加连接源 到原图每个点 的有向边sv  ,容量为;增加连接原图每个点 到汇 的有向边vt   ,容量为 (+ 2dv ) 。

代码:

  1 #include <map>
  2 #include <set>
  3 #include <cmath>
  4 #include <queue>
  5 #include <stack>
  6 #include <cstdio>
  7 #include <string>
  8 #include <vector>
  9 #include <cstdlib>
 10 #include <cstring>
 11 #include <sstream>
 12 #include <iostream>
 13 #include <algorithm>
 14 #include <functional>
 15 using namespace std;
 16 #define rep(i,a,n) for (int i=a;i<n;i++)
 17 #define per(i,a,n) for (int i=n-1;i>=a;i--)
 18 #define pb push_back
 19 #define mp make_pair
 20 #define all(x) (x).begin(),(x).end()
 21 #define SZ(x) ((int)(x).size())
 22 typedef vector<int> VI;
 23 typedef long long ll;
 24 typedef pair<int, int> PII;
 25 const ll mod = 1e9 + 7;
 26 const int inf = 0x3f3f3f3f;
 27 const double eps = 1e-10;
 28 const double pi = acos(-1.0);
 29 // head
 30
 31 struct edge { int to; double cap; int rev; };
 32 const int MAX_V = 110;
 33 vector<edge> G[MAX_V];
 34 int level[MAX_V];
 35 int iter[MAX_V];
 36
 37 void add_edge(int from, int to, double cap) {
 38     G[from].pb(edge{ to, cap, (int)G[to].size() });
 39     G[to].pb(edge{ from, 0, (int)G[from].size() - 1 });
 40 }
 41
 42 void bfs(int s) {
 43     memset(level, -1, sizeof(level));
 44     queue<int> que;
 45     level[s] = 0;
 46     que.push(s);
 47     while (!que.empty()) {
 48         int v = que.front(); que.pop();
 49         rep(i, 0, G[v].size()) {
 50             edge &e = G[v][i];
 51             if (e.cap > 0 && level[e.to] < 0) {
 52                 level[e.to] = level[v] + 1;
 53                 que.push(e.to);
 54             }
 55         }
 56     }
 57 }
 58
 59 double dfs(int v, int t, double f) {
 60     if (v == t) return f;
 61     for (int &i = iter[v]; i < G[v].size(); i++) {
 62         edge &e = G[v][i];
 63         if (e.cap > 0 && level[v] < level[e.to]) {
 64             double d = dfs(e.to, t, min(f, e.cap));
 65             if (d > 0) {
 66                 e.cap -= d;
 67                 G[e.to][e.rev].cap += d;
 68                 return d;
 69             }
 70         }
 71     }
 72     return 0;
 73 }
 74
 75 double max_flow(int s, int t) {
 76     double flow = 0;
 77     while (1) {
 78         bfs(s);
 79         if (level[t] < 0) return flow;
 80         memset(iter, 0, sizeof(iter));
 81         double f;
 82         while ((f = dfs(s, t, inf)) > 0) flow += f;
 83     }
 84 }
 85
 86 struct Rel { int x, y; }p[1010];
 87 int degree[MAX_V];
 88 int n, m, s, t;
 89
 90 void construct_graph(double mid) {
 91     rep(i, 0, MAX_V) G[i].clear();
 92     rep(i, 1, n + 1) add_edge(s, i, m), add_edge(i, t, m + 2 * mid - degree[i]);
 93     rep(i, 0, m) add_edge(p[i].x, p[i].y, 1.0), add_edge(p[i].y, p[i].x, 1.0);
 94 }
 95
 96 int vis[MAX_V], sum;
 97 void dfs_travel(int v) {
 98     sum++;
 99     vis[v] = 1;
100     rep(i, 0, G[v].size()){
101         edge &e = G[v][i];
102         if (e.cap > eps && !vis[e.to]) dfs_travel(e.to);
103     }
104 }
105
106 int main() {
107     cin >> n >> m;
108     if (m == 0) return puts("1\n1"), 0;
109     s = 0, t = n + 1;
110     rep(i, 0, m) {
111         scanf("%d%d", &p[i].x, &p[i].y);
112         degree[p[i].x]++;
113         degree[p[i].y]++;
114     }
115     double lb = 0, ub = m, precision = 1.0 / n / n;
116     while (ub - lb >= precision) {
117         double mid = (lb + ub) / 2;
118         construct_graph(mid);
119         double hg = (n*m - max_flow(s, t)) / 2;
120         if (hg > eps) lb = mid;
121         else ub = mid;
122     }
123     construct_graph(lb);
124     max_flow(s, t);
125     dfs_travel(0);
126     cout << sum - 1 << endl;
127     rep(i, 1, n + 1) if (vis[i]) cout << i << endl;
128     return 0;
129 }
时间: 2024-11-03 22:05:26

POJ 3155 最大密度子图的相关文章

POJ 3155 Hard Life(最大密度子图)

POJ 3155 Hard Life 题目链接 最大密度子图模板题 代码: #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; const int MAXNODE = 1105; const int MAXEDGE = 100005; typedef double Type; const Type INF = 1e15;

POJ 3155 Hard Life(最大密度子图+改进算法)

Hard Life Time Limit: 8000MS   Memory Limit: 65536K Total Submissions: 9012   Accepted: 2614 Case Time Limit: 2000MS   Special Judge Description John is a Chief Executive Officer at a privately owned medium size company. The owner of the company has

poj 3155 Hard Life 最大密度子图

Hard Life Time Limit: 8000MS   Memory Limit: 65536K Total Submissions: 7598   Accepted: 2191 Case Time Limit: 2000MS   Special Judge Description John is a Chief Executive Officer at a privately owned medium size company. The owner of the company has

POJ Hard Life (最大密度子图)

Hard Life 做该题前需要先了解一些专有名词及定理. 希望你可以亲自看看2007年胡伯涛的论文! 有向图的闭合图(closure): 闭合图内任意点的任意后继也一定还在闭合图中. 题目: 给出N个人,有些人之间有联系,而有联系的两个人被认为是一个整体.如果,把人看作点,把关系看作边,则要求你求出 边 / 点 的比值最大.而这些点边之间必须是一个闭合图. 算法分析: 最大密度子图算法构造: 把原图中的无向边转换成两条有向边,容量为1. 设一源点,连接所有点,容量为U(取m). 设一汇点,所有

[POJ 3155] Hard Life

描述 http://poj.org/problem?id=3155 一个公司内部共n个员工,员工之间可能曾经因为小事有了过节,总是闹矛盾.若员工u和员工v有矛盾,用边(u, v)表示,共m个矛盾.最近,公司内部越来越不团结,要裁员.想得到一个被裁人员的清单,使得被裁人员间的不团结率最高.不团结率定义为被裁人员间的矛盾总数与被裁人员数的比值(不团结率= 被裁人员之间的矛盾总数/ 被裁人员数). 题解: 如果把一个矛盾定义为一条边,一位员工定义为一个点,那么这里的不团结率就对应着一个图的密度:图的一

poj3155--Hard Life(最大密度子图)

poj3155:题目链接 题目大意:给出了n个点,m条无向边,选一个集合M,要求集合中的边数/点数的最最大 参考:最小割模型在信息学竞赛中的应用 先做了0-1分数规划,然后最大权闭合图,然后是最大密度子图.最大密度子图要用到前两个知识点. 注意:精度问题,这个题的单调性会出现一段为0的值,所以要用二分逼近最左侧的那个,然后在二分完成后,要用low(左边界)再求一次,这样是最精确的 #include <cstdio> #include <cstring> #include <c

bzoj 1312 最大密度子图

晕,m=0是要输出1(弄的我还找管理员要数据,但明显题意是叫我们输出0呀) 最大密度子图,把边转换成点,然后二分答案,跑最大权闭合子图判定是否可行. 1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 #include <algorithm> 5 #define N 1110 6 #define oo 0x3f3f3f3f 7 using namespace std; 8 9 stru

Uvalive 7037 The Problem Needs 3D Arrays(最大密度子图)

题意:给一段子序列,定义密度:子序列中的逆序对数/子序列的长度 求这个序列的对大密度. 分析:将序列中的每个位置视作点,逆序对\(<i,j>\)之间表示点i与点j之间有一条无向边.所以就转化为了最大密度子图的模型. #include<bits/stdc++.h> using namespace std; #define eps 1e-7 #define INF 0x3f3f3f3f const int MAXN=1010;//点数的最大值 const int MAXM=400010

2017 计蒜之道 初赛 第三场 D. 腾讯狼人杀 (点边都带权的最大密度子图)

点边都带权的最大密度子图,且会有必须选的点. 写到一半没保存实验室断电,气炸.明天补详细题解. #include<bits/stdc++.h> using namespace std; const double eps = 1e-7; const int INF = 0x3f3f3f3f; const int MAXN= 405;//点数的最大值 const int MAXM= 1e6 + 10;//边数的最大值 #define captype double struct Edge{ int