GDKOI 2021 提高组 Day1 第一题 割(贪心+二分图染色)

GDKOI 2021 提高组 Day1 第一题 割

题目大意

  • 给出一种方案使 n n n个点 m m m条边分成两部分,两部分之间的边数 ≥ m 2 gefrac{m}{2} 2m
  • n ≤ 1 0 5 , m ≤ 2 ∗ 1 0 5 nle10^5,mle2*10^5 n105,m2105

题解

  • 没用的边删去后,剩下的部分是一张二分图,考虑贪心染色。
  • DFS的过程中,每到一个未染色的点,统计与它相邻的点的颜色,将它自己染为较少的那种,令这些点有 s s s个,即边共 s s s条,这样可以保证连出的边 ≥ s 2 gefrac{s}{2} 2s,那么最后连出的边 ≥ m 2 gefrac{m}{2} 2m

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100010
#define M 200010
int last[N], nxt[M * 2], to[M * 2], len = 1;
int co[N], sum = 0;
void add(int x, int y) {
	to[++len] = y;
	nxt[len] = last[x];
	last[x] = len;
}
void dfs(int k) {
	int s0 = 0, s1 = 0;
	for(int i = last[k]; i; i = nxt[i]) {
		s0 += (co[to[i]] == 0), s1 += (co[to[i]] == 1);
	}
	co[k] = (s1 <= s0);
	sum += min(s1, s0);
	for(int i = last[k]; i; i = nxt[i]) if(co[to[i]] == -1) dfs(to[i]);
}
int main() {
	int n, m, i, x, y;
	scanf("%d%d", &n, &m);
	for(i = 1; i <= m; i++) {
		scanf("%d%d", &x, &y);
		add(x, y), add(y, x);
	}
	memset(co, 255, sizeof(co));
	for(i = 1; i <= n; i++) if(co[i] == -1) dfs(i);
	for(i = 1; i <= n; i++) printf("%d ", co[i]);
	return 0;
}

自我小结

  • 其实这题在写的时候本意是贪心骗分,但在写的过程中发下这种做法正确性是保证的。
哈哈哈哈哈哈哈哈哈哈
原文地址:https://www.cnblogs.com/LZA119/p/14437606.html