Codeforces Round #589 (Div. 2) D. Complete Tripartite

题目链接: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 }
View Code

猜你喜欢

转载自www.cnblogs.com/mrzhangziheng/p/11611078.html