F. Strange Housing CF694 贪心
题目大意:
给你一张图,选择一部分点进行染色,要求:
- 如果一条边的两个点都没有被选,那么这条边删除
- 染色的这些点两辆不想连
- 最后必须是一个大小为 \(n\) 的连通图
是否存在一种方案,存在输出 \(YES\) ,不存在输出 \(NO\)
题解:
任意选一个点作为起点,直接贪心即可。
- 如果这个点存在一个相邻的点被染色了,则不选这个点
- 如果这个点所有相邻的点都没有染色,则选择这个点
这样如果最后是一个大小为 \(n\) 的连通图,那么就输出 \(YES\)
如果最后不是,那么输出 \(NO\)
推断:最后不是连通图,那么一定不存在一种染色方案
证明:如果存在一个点不在这个连通块中,那么说明这个点所有相连的点都不在这个连通图,那么这个点就满足条件2,这个点应该要被选中。
感觉这个题目够不上当F题,放到F是在考验我的心理素质吗。。。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 10;
vector<int>G[maxn];
int ans[maxn];
bool vis[maxn];
queue<int>que;
void bfs(int x) {
while (!que.empty()) que.pop();
que.push(x);
while (!que.empty()) {
int u = que.front();
que.pop();
if (vis[u]) continue;
vis[u] = true;
bool flag = true;
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if (ans[v] == 1) flag = false;
que.push(v);
}
ans[u] = flag;
}
}
vector<int>res;
int main(){
int T;scanf("%d",&T);
while(T--){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) G[i].clear(),ans[i] = -1,vis[i] = false;
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
bfs(1);
bool flag = true;
res.clear();
for(int i=1;i<=n;i++){
if(ans[i]==-1) flag = false;
if(ans[i]==1) res.push_back(i);
}
if(flag) {
printf("YES\n");
printf("%d\n",res.size());
for(auto x:res) printf("%d ",x);
printf("\n");
}
else printf("NO\n");
}
return 0;
}