原题链接






代码:
#include <iostream>
#include <stdio.h>
#include <queue>
#include <memory.h>
using namespace std;
typedef pair<int, int> P;
const int N = 110;
const int M = (1000 + N * 2) * 2;
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
int n, m, S, T;
int head[N], ne[M], to[M], idx = 1;
double f[M];
int dep[N], cur[N];
int deg[N];
bool st[N];
int ans;
queue<int> q;
P edges[M]; // 二分存边
void add(int u, int v, double c1, double c2)
{
to[ ++ idx] = v; f[idx] = c1; ne[idx] = head[u]; head[u] = idx;
to[ ++ idx] = u; f[idx] = c2; ne[idx] = head[v]; head[v] = idx;
}
void build(double g) // 建图函数
{
memset(head, 0, sizeof head);
idx = 1;
for (int i = 1; i <= m; i ++ ) // 这里是边的编号,不是idx
{
add(edges[i].first, edges[i].second, 1, 1); // 正向反向都是1,因为是无向图
}
for (int i = 1; i <= n; i ++ )
{
add(S, i, m, 0);
add(i, T, m + 2 * g - deg[i], 0);
}
}
bool bfs()
{
while (q.empty() == 0)
{
q.pop();
}
memset(dep, -1, sizeof dep);
q.push(S);
dep[S] = 0;
cur[S] = head[S];
while (q.empty() == 0)
{
int u = q.front();
q.pop();
for (int i = head[u]; i; i = ne[i] )
{
int v = to[i];
if (f[i] > eps && dep[v] == -1)
{
dep[v] = dep[u] + 1;
cur[v] = head[v];
if (v == T)
{
return 1;
}
q.push(v);
}
}
}
return 0;
}
double find(int u, double lim)
{
if (u == T)
{
return lim;
}
double flow = 0;
for (int i = cur[u]; i && flow < lim; i = ne[i] )
{
cur[u] = i;
int v = to[i];
if (dep[v] == dep[u] + 1 && f[i] > eps)
{
double d = find(v, min(f[i], lim - flow));
if (d <= eps)
{
dep[v] = 0;
}
flow += d;
f[i] -= d;
f[i ^ 1] += d;
}
}
return flow;
}
double dinic(double g)
{
build(g);
double ans = 0;
while (bfs())
{
ans += find(S, INF);
}
return ans;
}
void dfs(int u)
{
st[u] = 1;
if (u != S)
{
ans ++;
}
for (int i = head[u]; i; i = ne[i] )
{
int v = to[i];
if (st[v] == 0 && f[i] > 0)
{ // 不要忘了是沿着容量大于0的边走,而且是大于0,eps有锅
dfs(v);
}
}
}
int main()
{
scanf("%d%d", &n, &m);
S = 0;
T = n + 1;
for (int i = 1; i <= m; i ++ )
{
int a, b;
scanf("%d%d", &a, &b);
deg[a] ++;
deg[b] ++;
edges[i] = {a, b};
}
// 保证U比m大就可以
double l = 0, r = m;
while (r - l > eps)
{
double mid = (l + r) / 2;
double t = dinic(mid);
if (m * n - t > 0) // 判断答案是否在上
{
l = mid;
}
else
{
r = mid;
}
}
dinic(l);
dfs(S);
if (ans == 0)
{
printf("1\n1"); // 至少选择一名员工
return 0;
}
printf("%d\n", ans);
for (int i = 1; i <= n; i ++ )
{
if (st[i] == 1)
{
printf("%d\n", i);
}
}
return 0;
}