最大密集子图

最大密集子图的模板题

poj 3155

最大密集子图的定义就是选出来若干个点,连接他们的边必选,问$\frac{e}{v}$ 如何最大?
这里要用分数规划,之后用最大权闭合子图进行二分判断,从而求得最大密集子图
原理可以参考胡伯涛的论文

ac code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <cstdio>
using namespace std;
const int maxn = 205;
const int INF = 1e9+10;
const double eps = 1e-8;
struct Edge{
int to, rev;
double cap;
Edge(int _to, double _cap, int _rev):to(_to), cap(_cap), rev(_rev){}
};
vector<Edge> G[maxn];
int cnt[maxn];
int level[maxn];
int s, t;
int n, m;
int d[maxn];
void add_edge(int u, int v, double cap){
G[u].push_back(Edge(v, cap, G[v].size()));
G[v].push_back(Edge(u, 0, G[u].size()-1));
}
void bfs(int s){
memset(level, -1, sizeof(level));
queue<int> q;
q.push(s);
level[s] = 0;
while(!q.empty()){
int v = q.front();
q.pop();
for(int i=0; i<G[v].size(); i++){
Edge& e = G[v][i];
if(e.cap>eps&&level[e.to]<0){
level[e.to] = level[v]+1;
q.push(e.to);
}
}
}
}
double dfs(int v, int t, double flow){
if(v == t) return flow;
for(int& i=cnt[v]; i<G[v].size(); i++){
Edge& e = G[v][i];
if(e.cap>0&&level[v]<level[e.to]){
double d = dfs(e.to, t, min(flow, e.cap));
if(d>eps){
e.cap -= d;
G[e.to][e.rev].cap += d;
return d;//一旦有一条路径满足就立即返回!
}
}
}
return 0;
}
double max_flow(int s, int t){
double flow = 0;
for(;;){
//构造层次图
bfs(s);
//无法连通终点,结束访问
if(level[t]<0) return flow;
double f;
//cnt数组记录在递归的过程中的边的顺序。
memset(cnt, 0, sizeof(cnt));
//当存在增广路的时候不断的进行增广
while((f = dfs(s, t, INF))>eps){
//cout<<"qiu "<<f<<endl;
flow+=f;
}
}
}
int x[1024], y[1024];
void graph(double g){
for(int i=0; i<=n+1; i++){
G[i].clear();
}
for(int i=0; i<m; i++){
add_edge(x[i], y[i], 1.0), add_edge(y[i], x[i], 1.0);
}
for (int i = 1; i <= n; i++)
{
add_edge(s, i, m);
add_edge(i, t, m + 2 * g - d[i]);
}
}
int sum = 0;
bool vis[maxn];
void dfs_ans(int u){
sum++;
vis[u] = true;
for(int i=0; i<G[u].size(); i++){
Edge v = G[u][i];
if(v.cap>eps&&!vis[v.to]){
dfs_ans(v.to);
}
}
}
int main()
{
while(~scanf("%d%d", &n, &m)){
if(m == 0){
printf("1\n1\n");
continue;
}
for(int i=0; i<maxn; i++) d[i] = 0;
int u, v;
for(int i=0; i<m; i++){
scanf("%d%d", &x[i], &y[i]);
d[x[i]]++, d[y[i]]++;
}
s = 0;
t = n+1;
double l=0, r=m;
double mid;
const double presion = 1.0/n/n;
while(r-l>=presion){
mid = ((l+r)/2.0);
//cout<<l<<" "<<r<<" "<<mid<<endl;
graph(mid);
//未满流
//cout<<"out"<<endl;
if((n*m-max_flow(s, t))/2.0>eps) l=mid;
else r=mid;
}
graph(l);
max_flow(s, t);
sum = 0, memset(vis, 0, sizeof(vis));
dfs_ans(0);
printf("%d\n", sum-1);
for(int i=1; i<=n; i++) {
if(vis[i]) printf("%d\n", i);
}
}
return 0;
}

未解决的问题

文章目录
  1. 1. poj 3155
    1. 1.1. ac code
  2. 2. 未解决的问题
{{ live2d() }}