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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
| // 더 많은 정보는 42jerrykim.github.io 에서 확인하세요.
#include <bits/stdc++.h>
using namespace std;
struct Dinic {
struct Edge {
int to, rev;
double cap;
};
int N;
vector<vector<Edge>> graph;
vector<int> level, work;
const double EPS = 1e-9;
explicit Dinic(int n) : N(n), graph(n), level(n), work(n) {}
void addEdge(int u, int v, double c) {
Edge a{v, (int)graph[v].size(), c};
Edge b{u, (int)graph[u].size(), 0.0};
graph[u].push_back(a);
graph[v].push_back(b);
}
bool bfs(int s, int t) {
fill(level.begin(), level.end(), -1);
queue<int> q;
level[s] = 0;
q.push(s);
while (!q.empty()) {
int u = q.front(); q.pop();
for (const auto &e : graph[u]) {
if (level[e.to] < 0 && e.cap > EPS) {
level[e.to] = level[u] + 1;
q.push(e.to);
}
}
}
return level[t] >= 0;
}
double dfs(int u, int t, double f) {
if (u == t) return f;
for (int &i = work[u]; i < (int)graph[u].size(); i++) {
Edge &e = graph[u][i];
if (e.cap > EPS && level[e.to] == level[u] + 1) {
double ret = dfs(e.to, t, min(f, e.cap));
if (ret > EPS) {
e.cap -= ret;
graph[e.to][e.rev].cap += ret;
return ret;
}
}
}
return 0.0;
}
double maxflow(int s, int t) {
double flow = 0.0;
while (bfs(s, t)) {
fill(work.begin(), work.end(), 0);
while (true) {
double pushed = dfs(s, t, 1e100);
if (pushed <= EPS) break;
flow += pushed;
}
}
return flow;
}
// After running maxflow, get vertices reachable from s in residual graph
vector<int> mincut_reachable_from_source(int s) {
const double EPS2 = 1e-9;
vector<int> vis(N, 0);
queue<int> q;
vis[s] = 1;
q.push(s);
while (!q.empty()) {
int u = q.front(); q.pop();
for (const auto &e : graph[u]) {
if (!vis[e.to] && e.cap > EPS2) {
vis[e.to] = 1;
q.push(e.to);
}
}
}
return vis;
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
if (!(cin >> n >> m)) return 0;
vector<pair<int,int>> edges;
edges.reserve(m);
for (int i = 0; i < m; i++) {
int a, b; cin >> a >> b;
--a; --b;
edges.emplace_back(a, b);
}
// Trivial case: no edges -> any single person is optimal (ratio 0)
if (m == 0) {
cout << 1 << "\n" << 1 << "\n";
return 0;
}
auto build_and_flow = [&](double r, bool want_set, vector<int> &out_set)->double {
// Node indexing:
// 0..n-1: vertex nodes
// n..n+m-1: edge nodes
// s = n + m, t = n + m + 1
int S = n + m;
int T = n + m + 1;
int tot = n + m + 2;
const double INF = 1e100;
Dinic din(tot);
// s -> edge-node (capacity 1)
for (int i = 0; i < m; i++) {
int eNode = n + i;
din.addEdge(S, eNode, 1.0);
}
// edge-node -> endpoint vertex (INF)
for (int i = 0; i < m; i++) {
int u = edges[i].first;
int v = edges[i].second;
int eNode = n + i;
din.addEdge(eNode, u, INF);
din.addEdge(eNode, v, INF);
}
// vertex -> t (capacity r)
for (int v = 0; v < n; v++) {
din.addEdge(v, T, r);
}
double f = din.maxflow(S, T);
if (want_set) {
auto vis = din.mincut_reachable_from_source(S);
vector<int> pick;
for (int v = 0; v < n; v++) if (vis[v]) pick.push_back(v + 1); // 1-indexed
if (pick.empty()) {
// As a fallback to guarantee non-empty output
pick.push_back(1);
}
sort(pick.begin(), pick.end());
out_set = move(pick);
}
return f;
};
// Binary search r*: largest r with delta = m - maxflow > 0 holds for r < r*, and delta == 0 for r >= r*.
double lo = 0.0, hi = (double)m; // ratio is in [0, m]
for (int it = 0; it < 80; it++) {
double mid = (lo + hi) * 0.5;
vector<int> dummy;
double flow = build_and_flow(mid, false, dummy);
double delta = (double)m - flow; // max_{S} (|E(S)| - r|S|)
if (delta > 1e-9) lo = mid; else hi = mid;
}
double r_star = lo;
// Retrieve the set: bias slightly below r* to avoid tie picking the empty set
vector<int> answerSet;
build_and_flow(max(0.0, r_star - 1e-7), true, answerSet);
cout << (int)answerSet.size() << "\n";
for (int v : answerSet) cout << v << "\n";
return 0;
}
|