Complete Tripartite CodeForces - 1228D
题意
给出一个无向简单图,可能不连通,没有自环,没有重边。问能否将所有点划分成三个集合,每个集合中的所有点没有边直接连接,而且与其他两个集合中的所有点都有边直接连接(完全三分图)。
思路
先假设这个图是符合要求的,那么随意寻找一个开始染色,为起始点染色为1,所有与它直接相连的点染色为2,再任取一与起始点直接相连的点开始染色,所有与它相连的点,如果已经被染色为2,则将其染成3,(因为它既与1相连又与2相连),如果未被染色,则染色为1(因为它不与1相连)。然后根据完全三分图的要求来确定答案的正确性。
对于每一个连通块要求:
- 每种颜色都应该存在不为0。
- 与每个点相连的点的数量应该为另外两种颜色数量之和。
- 每条边所连的端点的颜色应当不同。
AC代码
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include<vector>
using namespace std;
#define ll long long
int fa[100005];
int color[100005];
vector<int> G[100005];
int sum[100005][4];
int n, m,u,v;
int Find(int x)
{
return x == fa[x] ? x : fa[x] = Find(fa[x]);
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
fa[i] = i;
for (int i = 0; i < m; i++)
{
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
for (int i = 1; i <= n; i++)
{
if (color[i] == 0)
{
color[i] = 1;
if (!G[i].size())
{
printf("-1");
return 0;
}
int to = G[i][0];
for (int j = 0; j < G[i].size(); j++)
{
int v = G[i][j];
if (color[v])
{
printf("-1");
return 0;
}
fa[v] = i;
color[v] = 2;
}
for (int j = 0; j < G[to].size(); j++)
{
int v = G[to][j];
if (v == i)
continue;
fa[v] = i;
if (color[v] == 0)
color[v] = 1;
else if (color[v] == 2)
color[v] = 3;
else
{
printf("-1");
return 0;
}
}
}
}
for (int i = 1; i <= n; i++)
{
sum[fa[i]][color[i]]++;
}
for (int i = 1; i <= n; i++)
{
if(sum[i][1]||sum[i][2]||sum[i][3])
{
if (!sum[i][1] || !sum[i][2] || !sum[i][3])
{
printf("-1");
return 0;
}
}
if (color[i] == 1)
{
if (sum[fa[i]][2] + sum[fa[i]][3] != G[i].size())
{
printf("-1");
return 0;
}
}
else if (color[i] == 2)
{
if (sum[fa[i]][1] + sum[fa[i]][3] != G[i].size())
{
printf("-1");
return 0;
}
}
else if (color[i] == 3)
{
if (sum[fa[i]][2] + sum[fa[i]][1] != G[i].size())
{
printf("-1");
return 0;
}
}
for (int j = 0; j < G[i].size(); ++j) {
int v = G[i][j];
if (color[v] == color[i]) {
printf("-1");
return 0;
}
}
}
for (int i = 1; i <= n; i++)
{
printf("%d ", color[i]);
}
return 0;
}