算法学习笔记 [网络流] AcWing 2324. 生活的艰辛

原题链接

image

image

image

image

image

image

代码:

#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;
	
}
posted @ 2021-11-13 22:12  RuntimeError-J  阅读(53)  评论(0)    收藏  举报