F. Strange Housing
题意
有 n n n 个点和 m m m 条边,对点进行染色。要求一条边的两个点不能都染色,并且删除两端都没有染色的边之后,图连通。请给出一种染色方案。
题解
- 暴力贪心即可。
- 首先如果图连通,则一定存在答案,不存在答案。
- BFS遍历所有的点。
- 如果当前节点没有染色,且相邻的所有节点没有染色,就染色,否则不染色。
- 如果当前节点已经染色,那么把相邻的所有节点标记不染色。
- 证明:显然这种方案不会存在一条边的两端都染色的情况,并且如果图不连通,一定是有一个点连接的所有点都不染色,而这样的点一定会在第一种情况下被染色,所以图一定是连通的。
代码
#pragma region
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for (int i = a; i <= n; ++i)
#pragma endregion
const int maxn = 3e5 + 5;
vector<int> g[maxn], ans;
int cnt, vis[maxn];
void init(int n) {
rep(i, 1, n) g[i].resize(0), vis[i] = 0;
ans.resize(0);
cnt = 0;
}
void dfs(int u) {
++cnt, vis[u] = 1;
for (auto v : g[u])
if (!vis[v]) dfs(v);
}
void bfs(int s) {
queue<int> q;
vis[s] = 2, ans.push_back(s);
q.push(s);
while (q.size()) {
int u = q.front();
q.pop();
for (auto v : g[u]) {
if (vis[v] != 1) continue;
if (vis[u] == 2) vis[v] = 3, q.push(v);
int flag = 1;
if (vis[u] == 3) {
for (auto vv : g[v]) flag &= (vis[vv] != 2);
if (flag) q.push(v), vis[v] = 2, ans.push_back(v);
}
}
}
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
int n, m;
scanf("%d%d", &n, &m);
init(n);
while (m--) {
int u, v;
scanf("%d%d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1);
if (cnt != n) {
puts("NO");
continue;
}
bfs(1);
printf("YES\n%d\n", (int)ans.size());
for (auto it : ans) printf("%d ", it);
puts("");
}
}