F. Strange Housing
题目传送门:
题目大意:
对于图中的n个点进行染色,一条边的两端不能同时染色。染色之后端点有染色的边会保留下来,要求染色之后的图连通。
思路:
1.显然当图连通时一定存在答案,否则不存在。
2.bfs遍历所有点:
如果当前节点没有染色,且相邻的所有点都没有染色,就染色,否则不染色。
如果当前节点已经染色,那么相邻的所有节点都不染色。
证明:显然这种方案不会存在一条边两个端点都染色的情况。其次,如果图不连通,一定是有一个点连接的所有点都不染色,而这样的点一定会存在第一种情况下被染色,所以图一定是连通的。
#include<bits/stdc++.h>
using namespace std;
const int N=6e5+10;
int head[N];
struct node
{
int to,next;
}tr[N];
int cent=0;
int n,m;
void add(int u,int v)
{
tr[cent].to=v;
tr[cent].next=head[u];
head[u]=cent++;
}
int ans[N],f[N];
int res=0;
bool bfs()//检查图是否连通
{
for(int i=0;i<=n+10;i++)//标记有没有遍历到过
ans[i]=0;
ans[1]=1;
queue<int>que;
que.push(1);
int num=1;
while(!que.empty())
{
int now=que.front();
que.pop();
for(int i=head[now];~i;i=tr[i].next)
{
int to=tr[i].to;
if(ans[to]==0)
{
ans[to]=1;
que.push(to);
num++;
}
}
}
if(num==n) return true;
else return false;
}
void solve()
{
for(int i=0;i<=n+10;i++)
{
ans[i]=0;
f[i]=0;
}
f[1]=1;
queue<int>que;
que.push(1);
while(!que.empty())
{
int now=que.front();
que.pop();
int flag=0;
for(int i=head[now];~i;i=tr[i].next)
{
int to=tr[i].to;
if(ans[to]==1)
flag=1;
if(f[to]==0)
{
f[to]=1;
que.push(to);
}
}
if(flag==0)
{
ans[now]=1;
res++;
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=0;i<=n+10;i++) head[i]=-1;
cent=0;
res=0;
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
if(!bfs()) printf("NO\n");
else
{
solve();
printf("YES\n");
printf("%d\n",res);
for(int i=1;i<=n;i++)
if(ans[i]==1) printf("%d ",i);
printf("\n");
}
}
//system("pause");
return 0;
}