解析详见:最小割模型在信息学中的应用
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 1000+10;
const double inf=0x3f3f3f3f;
const double eps = 1e-6;
int S, T;
int n, m;
typedef pair<int, int> P;
int de[maxn];
struct node {
int t;
double v;
int next;
}edge[100000+10];
int head[maxn];
int level[maxn];
int vis[maxn];
int cnt=0;
void init() {
cnt = 0;
memset(head, -1, sizeof(head));
}
struct Edge {
int u, v;
}E[maxn];
void add(int u, int v, double c) {
edge[cnt].t = v;
edge[cnt].v = c;
edge[cnt].next = head[u];
head[u] = cnt;
cnt++;
edge[cnt].t = u;
edge[cnt].v = 0.0;
edge[cnt].next = head[v];
head[v] = cnt;
cnt++;
}
bool bfs() {
int q[maxn], front=0, tail = 0;
memset(level, -1, sizeof(level));
level[S] = 1;
q[tail++] = S;
while (tail > front) {
int u = q[front];
front++;
if (u == T)
return true;
for (int i=head[u]; i!=-1; i=edge[i].next) {
int v = edge[i].t;
if (level[v] == -1 && edge[i].v > 0) {
level[v] = level[u]+1;
q[tail++] = v;
}
}
}
return false;
}
double dfs(int u, double minf) { // 增广多条路
if (u == T)
return minf;
double ret = 0; //记录所有增广路的流量和
for (int i=head[u]; i!=-1; i=edge[i].next) {
int v = edge[i].t;
double f;
if (level[v] == level[u]+1 && edge[i].v > 0) {
double Min = min(minf-ret, edge[i].v);
f = dfs(v, Min);
edge[i].v -= f;
edge[i^1].v += f;
ret += f;
if (ret == minf)
return ret;
}
}
return ret;
}
double dinic() {
double flow = 0.0;
while (bfs())
flow += dfs(S, inf*1.0);
return flow;
}
void build(double g) {
for (int i=1; i<=n; i++)
add(S, i, m), add(i, T, m*1.0+2*g-de[i]*1.0);
for (int i=0; i<m; i++)
add(E[i].u, E[i].v, 1.0), add(E[i].v, E[i].u, 1.0);
}
int cunt=0;
void DFS(int u) {
vis[u] = 1;
cunt++;
for (int i=head[u]; i!=-1; i=edge[i].next) {
int v = edge[i].t;
if (vis[v] == 0 && edge[i].v > 0)
DFS(v);
}
}
int main() {
while (~scanf("%d%d", &n , &m)) {
if (m == 0) {
puts("1\n1\n");
continue;
}
S = 0, T=n+1;
for (int i=0; i<m; i++)
scanf("%d%d", &E[i].v, &E[i].u),
de[E[i].v]++, de[E[i].u]++;
double l=0, r=m;
while (r-l >= 1./n/n) {
double mid = (r+l)/2.0;
init();
build(mid);
double res = dinic();
res = (m*n*1.0-res)/2.0;
if (res > eps)
l = mid;
else
r = mid;
}
cunt=0;
memset(vis, 0, sizeof(vis));
init();
build(l);
dinic();
DFS(S);
printf("%d\n", cunt-1);
for (int i=1; i<=n; i++)
if (vis[i] == 1)
printf("%d\n", i);
}
return 0;
}