题意:
有 n 个点和 m 条边,对点进行染色。要求一条边的两个点不能都染色,并且删除两端都没有染色的边之后,图连通。请给出一种染色方案。
题解:
第一反应就是01染色,但是题目是有可能存在奇环的,那怎么办?
01染色是保证1和1,0和0都不能相邻,如果把1当做染色,根据本题,0是可以相邻的,那我们把01染色的dfs改成bfs的形式,也就是与1相邻的点都是0,然后对于每个0,所能到的下一个点就是1,然后对1操作,1的周围都是0,这样循环进行就可以
BFS遍历所有的点。
- 如果当前节点没有染色,且相邻的所有节点没有染色,就染色,否则不染色。
- 如果当前节点已经染色,那么把相邻的所有节点标记不染色。
证明:显然这种方案不会存在一条边的两端都染色的情况,并且如果图不连通,一定是有一个点连接的所有点都不染色,而这样的点一定会在第一种情况下被染色,所以图一定是连通的。
当然如果图本身就不连通直接输出NO
u1s1,div2的F题比我想象的要简单多
代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
#include<map>
using namespace std;
#define LL long long
#define eps (1e-8)
const int maxn = 3e5 + 10;
const int inf = 0x3f3f3f3f;
const LL mod = 1e9 + 7;
struct node
{int v, nxt;
}e[maxn << 1];
int head[maxn], cnt;
void add(int u, int v)
{e[++cnt].v = v;e[cnt].nxt = head[u];head[u] = cnt;
}
int vis[maxn];//标记为1是染色,0位不染色,-1位还未遍历的点
queue<int>q;
void bfs(int u)
{vis[u] = 1;for (int i = head[u]; i; i = e[i].nxt){int v = e[i].v;// if (vis[v] == -1){vis[v] = 0; q.push(v);//存的都是不染色的点}}
}
void solve()
{while (!q.empty()){int u = q.front();q.pop();for (int i = head[u]; i; i = e[i].nxt){int v = e[i].v;//v为染色点 if (vis[v] == -1){bfs(v);}}}
}
int main()
{int t;scanf("%d", &t);while (t--){cnt = 0;int n, m;scanf("%d%d", &n, &m);for (int i = 0; i <= n; i++){head[i] = 0;vis[i] = -1;}int u, v;while (m--){scanf("%d%d", &u, &v);add(u, v), add(v, u);}bfs(1);solve();int flag = 1, ans = 0;for (int i = 1; i <= n; i++){if (vis[i] == 1)ans++;else if (vis[i] == -1)//说明有的点没有遍历到,图不连通 {flag = 0;}}if (flag){printf("YES\n");printf("%d\n", ans);for (int i = 1; i <= n; i++){if (vis[i] == 1)printf("%d ", i);}printf("\n");}else{printf("NO\n");}}return 0;
}