`
阿尔萨斯
  • 浏览: 4147719 次
社区版块
存档分类
最新评论

Codeforces 387D George and Interesting Graph(二分图匹配)

 
阅读更多

题目链接:Codeforces 387D George and Interesting Graph


题目大意:定义一种有趣图:有向无子环图,存在一个根磨合任意节点有一去路和一回路(本身也有),然后除去根以外的所有点的入度和出度均为2。现在给出一张图,问说最少给进行几次操作可以使得图变成有趣图,操作可以是删除和添加一条边。


解题思路:枚举根,判断以该节点为根需要几次操作,维护最小值。

确定根后,计算出为满足根与所有点的有回路去路需要几步操作,n*2-1-s(s为与根相连的边,s=ind[root]+out[root]-g[root][root]);然后除去根后,其他的点的出度和入度均为1,首尾相接即可,用二分图匹配计算出已经存在的边可以满足几个。


#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;
const int N = 505;

int n, m, g[N][N], ind[N], out[N], v[N], p[N];


void init () {
	memset(g, 0, sizeof(g));
	memset(ind, 0, sizeof(ind));
	memset(out, 0, sizeof(out));

	int a, b;
	scanf("%d%d", &n, &m);
	for (int i = 0; i < m; i++) {
		scanf("%d%d", &a, &b);
		g[a][b] = 1;
		out[a]++; ind[b]++;
	}
}

bool find (int r, int u) {
	for (int i = 1; i <= n; i++) {
		if (i == r || !g[u][i]) continue;
		if (v[i]) continue;
		v[i] = 1;
		if (p[i] == -1 || find(r, p[i])) {
			p[i] = u;
			return true;
		}
	}
	return false;
}

int handle(int r) {
	int ans = 0;
	memset(p, -1, sizeof(p));
	for (int i = 1; i <= n; i++) {
		if (i == r) continue;
		memset(v, 0, sizeof(v));
		if (find(r, i)) ans++;
	}
	return ans;
}

int solve (int r) {
	int s = ind[r] + out[r] - g[r][r];
	int ans = 2 * n - 1 - s;
	int f = handle(r);
	ans = ans + m - s - f;
	ans = ans + n - 1 - f;
	return ans;
}

int main () {
	init();
	int ans = 1 << 30;
	for (int i = 1; i <= n; i++) ans = min(ans, solve(i));
	printf("%d\n", ans);
	return 0;
}


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics