题目链接:https://codeforces.com/contest/1228/problem/D
题目大意:给一张n个点的无向图,无自环,不保证联通,问是否能三分这张图。对于每个集合的要求为,集合内部的点,两两之间不能有边相连,不同集合之间的点都需要有边相连。如果可以三分这张图,输出方案;如果不能,输出-1。
题解:
先判断图是否联通,如果不联通,直接输出-1。
将图染色。
具体地说,先将所有的点染色为1,从第一个点开始遍历这张图,(假设此时遍历到了点u)如果u和v之间有边且颜色相同,则将v换一种颜色(即,color[v]++);如果u和v之间有边且颜色不同,continue。
染色之后判断染色方案是否合法。
具体地说,如果颜色1 || 颜色2 || 颜色3 有一个集合为0,说明方案不合法,输出-1。
判断每个集合里的元素的度数是否等于(n - 集合大小)。如果有一个点不满足 度数 = (n - 集合大小),说明方案不可行,输出-1。
比如说,对于题目第一个样例,二号点属于第二个集合,第二个集合的大小为2,二号点需要和第二个集合之外所有的点都有边,所以二号点的度数一定要等于6 - 2 = 4才会合法。
如果上述没有出现不合法的情况,输出方案。
1 #include<iostream> 2 #include<vector> 3 #include<map> 4 #include<algorithm> 5 #include<queue> 6 #include<cstdio> 7 #include<cmath> 8 #include<string> 9 #include<set> 10 #include<complex> 11 #include<cstdio> 12 #include<cstring> 13 #include<stack> 14 #include<iomanip> 15 #include<bitset> 16 #include<typeinfo> 17 #include<random> 18 #include<unordered_map> 19 #include<unordered_set> 20 using namespace std; 21 22 const int maxn = 3e5 + 10; 23 24 int cnt; 25 int n, m; 26 int x, y; 27 vector<int> G[maxn]; 28 int vis[maxn], color[maxn], deg[maxn]; 29 30 void dfs(int x){ 31 vis[x] = cnt; 32 for(int i = 0; i < G[x].size(); i++){ 33 int y = G[x][i]; 34 if(vis[y]) continue; 35 dfs(y); 36 } 37 } 38 39 int main(){ 40 scanf("%d %d", &n, &m); 41 for(int i = 1; i <= m; i++){ 42 scanf("%d %d", &x, &y); 43 G[x].push_back(y); 44 G[y].push_back(x); 45 deg[x]++; // 度数 46 deg[y]++; // 度数 47 } 48 for(int i = 1; i <= n; i++){ // 判断联通 49 if(!vis[i]){ 50 cnt++; 51 dfs(i); 52 } 53 } 54 if(cnt >= 2){ // 不联通,不合法 55 printf("-1\n"); 56 return 0; 57 } 58 for(int i = 1; i <= n; i++) color[i] = 1; 59 for(int i = 1; i <= n; i++){ 60 for(int j = 0; j < G[i].size(); j++){ 61 int v = G[i][j]; 62 if(color[i] != color[v]) continue; // 两点属于不同集合 63 else color[v]++; // 两点属于相同集合,将点v换一种颜色 64 } 65 } 66 int cnt_one = 0, cnt_two = 0, cnt_three = 0; // 集合1 2 3大小 67 for(int i = 1; i <= n; i++){ 68 if(color[i] == 1) cnt_one++; 69 else if(color[i] == 2) cnt_two++; 70 else cnt_three++; 71 } 72 if(cnt_one == 0 || cnt_two == 0 || cnt_three == 0){ // 如果有集合为0,不合法 73 printf("-1\n"); 74 return 0; 75 } 76 for(int i = 1; i <= n; i++){ // 判断集合中的点是否满足度数的要求 77 if(color[i] == 1 && deg[i] != n - cnt_one){ 78 printf("-1\n"); 79 return 0; 80 } 81 else if(color[i] == 2 && deg[i] != n - cnt_two){ 82 printf("-1\n"); 83 return 0; 84 } 85 else if(color[i] == 3 && deg[i] != n - cnt_three){ 86 printf("-1\n"); 87 return 0; 88 } 89 } 90 for(int i = 1; i <= n; i++){ // 输出方案 91 printf("%d ", color[i]); 92 } 93 printf("\n"); 94 return 0; 95 }