CF830E Perpetual Motion Machine

题面

题解

神仙构造题。

分五种情况考虑:

  • 如果存在一个环,那么令环上的点权值为\(1\),其余点权值为\(0\)
  • 如果存在一个度数大于\(3\)的点,令这个点的权值为\(2\),和它相邻的点权值为\(1\),否则权值为\(0\)
  • 如果存在两个度数等于\(3\)的点,令这两个点的路径上点的权值为\(2\),其余的点权值为\(1\)
  • 如果只有一个点度数为\(3\),那么这张图一定是这个点伸出三条链,设三条链的长度分别为\(l_1, l_2, l_3\),那么有解当且仅当\(\frac 1{l_1 + 1} + \frac 1{l_2 + 1} + \frac 1{l_3 + 1} \leq 1\)
  • 如果没有点度数为\(3\),可以证明一定无解。

于是就可以按照结论欢乐构造了。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)

inline int read()
{
	int data = 0, w = 1; char ch = getchar();
	while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
	if (ch == '-') w = -1, ch = getchar();
	while (ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = getchar();
	return data * w;
}

const int maxn(1e5 + 10);
struct edge { int next, to; } e[maxn << 1];
int head[maxn], e_num, n, m, vis[maxn], d[maxn], deg[maxn];
std::vector<int> vec[3];
inline void add_edge(int from, int to)
{
	e[++e_num] = (edge) {head[from], to};
	head[from] = e_num, ++deg[to];
}

void Set(int x)
{
	vis[x] = 0; if (!d[x]) d[x] = 1;
	for (int i = head[x]; i; i = e[i].next)
		if (vis[e[i].to]) Set(e[i].to);
}

int findCir(int x, int f)
{
	vis[x] = 1;
	for (int i = head[x]; i; i = e[i].next)
		if (!vis[e[i].to]) { if (findCir(e[i].to, x)) return 1; }
		else if (e[i].to != f) return 1;
	return 0;
}

int findDeg(int x, int f)
{
	if (f && deg[x] == 3) return d[x] = 2, 1;
	for (int i = head[x]; i; i = e[i].next)
		if (e[i].to != f) if (findDeg(e[i].to, x)) { d[x] = 2; return 1; }
	return 0;
}

void dfs(int x, int f, std::vector<int> &v)
{
	v.push_back(x);
	for (int i = head[x]; i; i = e[i].next)
		if (e[i].to != f) dfs(e[i].to, x, v);
}

int main()
{
	for (int T = read(); T--; )
	{
		n = read(), m = read();
		memset(head, 0, (n + 1) << 2), memset(vis, 0, (n + 1) << 2);
		memset(d, 0, (n + 1) << 2), memset(deg, 0, (n + 1) << 2), e_num = 0;
		for (int i = 1, a, b; i <= m; i++)
			a = read(), b = read(), add_edge(a, b), add_edge(b, a);
		int f = 0;
		for (int i = 1; !f && i <= n; i++)
			if (!vis[i]) if ((f = findCir(i, 0))) Set(i);
		for (int i = 1; !f && i <= n; i++)
			if (deg[i] > 3) { d[i] = 2, Set(i), f = 1; }
		for (int i = 1; !f && i <= n; i++)
			if (deg[i] == 3) if ((f = findDeg(i, 0)))
				memset(vis, 1, sizeof vis), Set(i);
		for (int i = 1; !f && i <= n; i++) if (deg[i] == 3)
		{
			int cur = 0; vec[0].clear(), vec[1].clear(), vec[2].clear();
			for (int j = head[i]; j; j = e[j].next) dfs(e[j].to, i, vec[cur++]);
			if (vec[0].size() > vec[1].size()) std::swap(vec[0], vec[1]);
			if (vec[0].size() > vec[2].size()) std::swap(vec[0], vec[2]);
			if (vec[1].size() > vec[2].size()) std::swap(vec[1], vec[2]);
			if (vec[1].size() == 1 || (vec[0].size() == 1 && vec[1].size() == 2
					&& vec[2].size() < 5)) continue;
			f = 1;
			if (vec[2].size() >= 5)
			{
				d[i] = 6, d[vec[0][0]] = 3, d[vec[1][0]] = 4, d[vec[1][1]] = 2;
				for (int j = 0; j < 5; j++) d[vec[2][j]] = 5 - j;
			}
			else
			{
				d[i] = (vec[0].size() + 1) * (vec[1].size() + 1) * (vec[2].size() + 1);
				for (int j = 0; j < 3; j++) for (int k = 0; k < (int) vec[j].size(); k++)
					d[vec[j][k]] = d[i] / (vec[j].size() + 1) * (vec[j].size() - k);
			}
		}
		if (!f) { puts("NO"); continue; } puts("YES");
		for (int i = 1; i <= n; i++) printf("%d%c", d[i], " \n"[i == n]);
	}
	return 0;
}
posted @ 2019-07-24 21:36  xgzc  阅读(441)  评论(4编辑  收藏  举报