牛客小白月赛43 F 全体集合

题目链接 F 全体集合

题目大意

给出\(n\)个点\(m\)条边的无向图,给出\(k\)个点上分别有一个人,每个人一次只能走到一个相邻的节点,问有没有一种可能让这些人都走到一个点。

思路

考虑使用二分图染色:

  1. 如果染色成功,说明这个图是二分图,那么对于不同颜色的点永远不可能走到一起,题目也说了这个图是联通的,所以说如果这\(k\)个点颜色相同,那么一定可以走到一起。

  2. 如果染色不成功,那么一定可以,因为有一个性质,如果一个图没有奇数环,那么一定可以被染成二分图,所以说不是二分图就肯定存在奇数环,而存在奇数环就说明一个点可以围着奇数环走一圈改变颜色。

// Problem: 全体集合
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/11220/F
// Memory Limit: 524288 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>

using namespace std;

const int N = 2E5 + 10, M = 5e5 + 10;
int h[N], e[M * 2], ne[M * 2], idx;
int a[N];
int color[N];

void add(int a, int b) {
	e[idx] = b, ne[idx] = h[a], h[a] = idx++; 
}

bool dfs(int u, int c) {
	color[u] = c;
	for (int i = h[u]; i != -1; i = ne[i]) {
		int j = e[i];
		if (!color[j]) {
			if (!dfs(j, 3 - c)) return false;
		} else if (color[j] == c) return false;
	}
	
	return true;
}

int main() {
	int n, m, k;
	scanf("%d%d%d", &n, &m, &k);
	
	memset(h, -1, sizeof h);
	while (m--) {
		int a, b;
		scanf("%d%d", &a, &b);
		add(a, b), add(b, a);
	}
    
    for (int i = 1; i <= k; i++) scanf("%d\n", &a[i]);
	
	bool t = dfs(1, 1);
	if (!t) puts("YES");
	else {
		bool ok = true;
		/*
		for (int i = 1; i <= k; i++) {
			cout << color[a[k]] << " ";
		}
		puts("");*/
		for (int i = 1; i <= k - 1; i++) {
			if (color[a[i]] != color[a[i + 1]]) {
				ok = false;
				break;
			}
		}
		if (ok) puts("YES");
		else puts("NO");
	}
	
    return 0;
}
		

上一篇:[cf1428H]Rotary Laser Lock


下一篇:AcWing 算法基础课 图论