Complete Tripartite CodeForces - 1228D

Complete Tripartite CodeForces - 1228D

题意

给出一个无向简单图,可能不连通,没有自环,没有重边。问能否将所有点划分成三个集合,每个集合中的所有点没有边直接连接,而且与其他两个集合中的所有点都有边直接连接(完全三分图)。

思路

先假设这个图是符合要求的,那么随意寻找一个开始染色,为起始点染色为1,所有与它直接相连的点染色为2,再任取一与起始点直接相连的点开始染色,所有与它相连的点,如果已经被染色为2,则将其染成3,(因为它既与1相连又与2相连),如果未被染色,则染色为1(因为它不与1相连)。然后根据完全三分图的要求来确定答案的正确性。
对于每一个连通块要求:

  1. 每种颜色都应该存在不为0。
  2. 与每个点相连的点的数量应该为另外两种颜色数量之和。
  3. 每条边所连的端点的颜色应当不同。

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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值