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