【Codeforces Round #694 (Div. 1) D】Strange Housing
题目链接
翻译
让你在 \(n\) 个点上放老师,使得这 \(n\) 个点任意两个点之间都有路径。
但是所给的路径要激活才能用,而激活的条件就是路径连接的两个点中,有一个点放了老师。
当然一条路径不能两个端点都放老师,不然他们会打架 2333
输出任意一个合法的方案即可。
题解
随便找一个没染色的点 \(u\),染成黑色。
然后把所有和 \(u\) 相邻的点集 \(V\) 都染成白色。
这样,保证了这些白色的点都有从 \(u\) 开始的路径可达。
并且,这样做了之后,也能够保证这个黑色节点 \(u\) 不会有其他黑色节点和它相连。
紧接着,我们再从刚刚染成白色的 \(V\) 中,找一个点 \(v\),然后对于和它相邻的未染色的节点 \(x\)
把 \(x\) 看成是新的 \(u'\), 然后对这个新的 \(u'\) 也染成黑色,之后同样地,将与 \(u'\) 相邻的所有点都染成白色。
重复上述步骤,直到所有的点都被染色了为止。
这样操作一番之后,所有黑色的节点之间都仅隔着一个白色的点,所以可以互相到达。
而每个黑色的节点周围都是白色,保证所有白色节点也可以到达。并且,黑色节点周围都是白色,不会有嘿嘿的冲突。
perfect!
实现的时候,一定要注意,先把周围点都染成白色再找未染色的点...不要染了一个白色之后就跟着找这个白色的出度...
代码
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N = 3e5;
int n, m;
vector<int> g[N + 10];
int vis[N + 10],flag[N + 10],cnt;
queue<int> dl;
void dfs(int x){
cnt++;
vis[x] = 1;
int len = g[x].size();
vector<int> v;
v.clear();
for (int i = 0;i < len; i++){
int y = g[x][i];
if (vis[y] == 0){
continue;
}
vis[y] = 0;
v.push_back(y);
}
for (int y:v){
int len2 = g[y].size();
for (int j = 0;j < len2; j++){
int yy = g[y][j];
if (vis[yy] == -1){
dl.push(yy);
}
}
}
}
int main() {
#ifdef LOCAL_DEFINE
freopen("in.txt", "r", stdin);
#endif
ios::sync_with_stdio(0), cin.tie(0);
int T;
cin >> T;
while (T--) {
cin >> n >> m;
for (int i = 1;i <= n; i++){
g[i].clear();
vis[i] = -1;
flag[i] = 0;
}
for (int i = 1;i <= m; i++){
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
cnt = 0;
dl.push(1);
while (!dl.empty()){
int x = dl.front();dl.pop();
if (vis[x] == -1){
dfs(x);
}
}
bool ok = true;
for (int i = 1;i <= n; i++){
if (vis[i] == -1){
ok = false;
break;
}
}
if (!ok){
cout << "NO" << endl;
continue;
}
cout << "YES" << endl;
cout << cnt << endl;
for (int i = 1;i <= n; i++){
if (vis[i] == 1){
cout << i << " ";
}
}
cout << endl;
}
return 0;
}