P10851 [EGOI2024] Make Them Meet / 活动面基
构造题做的太少了,感觉这题是非常厉害的构造题。
考虑菊花图。菊花图结构非常简单,我的做法是先让所有点颜色相同,这样如果两个人分别在叶子上就可以在根相遇,否则一定会有一人走到根上,再与叶子挨个匹配即可。
考虑链的做法。我们可以考虑把两个人往中间赶,他们肯定可以相遇。但是这种想法非常不好构造方案,想想有没有别的方法?转换思路,我们很难把人往中间赶,但是我们可以将他们都往同一方向走,到边上就会反弹,这样也能让他们相遇。
具体的,对于每一轮,奇数轮
然后考虑树的做法。有了链的方法,树的构造方法也可以很自然的想到。我们按深度奇偶性染色,向刚刚一样。我们还需对于树根
现在考虑将树的构造套到一般图上。
理清思路,考虑一般图要有哪些性质才能使用树的构造方法?
- 对于任意节点
, 的任意两个儿子之间不能连边。 - 对于根节点
, 不能与选出的 的任意儿子连边。
实际上是要寻找一个合法的生成树,显然按 dfs 序生成的树是可以完美的满足性质一的,如果跑出来的是一条链,则可以直接用链的构造方法。否则,我们要找到根,使得根满足性质二。
我们找到一个按 dfs 序生成的树的分叉点,使得该点子树内没有其它分叉点(即这个点下挂有若干条链)。直接找最深的就行。为什么要找到最深的?因为在接下来的步骤中会有不好处理的地方,之后会讲。
设这个点为
如果
生成完后怎么做?这就体现出找最深的分叉点的优越性了。我们注意到生成出来的树的根节点只有两个儿子,并且子树分别为一棵正常的树和一条链。我们采取一般性的方法,奇数轮让深度为
这样构造可以发现,若一个人在子树中,他上去会在
来分析一下最劣情况,应该是两个人都在链中,其中一个先到根部然后进入子树,而另一个人则走回链底,他们刚好错开了。这样如果是最劣的话,设链的长度为
终于做完啦!
代码:
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = l; i <= r; ++ i)
#define rrp(i, l, r) for (int i = r; i >= l; -- i)
#define pii pair <int, int>
#define eb emplace_back
#define id(x, y) n * ((x) - 1) + (y)
#define ls p << 1
#define rs ls | 1
#define MN 1000000000000000000
using namespace std;
using namespace __gnu_cxx;
constexpr int N = 100 + 5, P = 1e9;
constexpr double PI = acos (-1.0);
inline int rd () {
int x = 0, f = 1;
char ch = getchar ();
while (! isdigit (ch)) {
if (ch == '-') f = -1;
ch = getchar ();
}
while (isdigit (ch)) {
x = (x << 1) + (x << 3) + ch - 48;
ch = getchar ();
}
return x * f;
}
int n, m;
int col[N];
bool e[N][N], vis[N];
void init () {
rep (i, 1, n) col[i] = i;
}
void put () {
rep (i, 1, n) printf ("%d ", col[i]);
puts ("");
}
int id[N], tot;
vector <int> t[N], G[N];
int dep[N], fa[N];
void dfs (int u) {
vis[u] = 1; id[++ tot] = u;
for (auto v : G[u]) {
if (vis[v]) continue;
dep[v] = dep[u] + 1; fa[v] = u; dfs (v);
}
rep (v, 1, n) {
if (! e[u][v] || vis[v]) continue;
dep[v] = dep[u] + 1; fa[v] = u; dfs (v);
}
}
int main () {
// freopen ("1.in", "r", stdin);
// freopen ("1.out", "w", stdout);
dep[0] = -1;
n = rd (), m = rd ();
int T = 420;
rep (i, 1, m) {
int u = rd () + 1, v = rd () + 1;
e[u][v] = e[v][u] = 1;
} dfs (1);
rep (i, 1, n) t[fa[i]].eb (i);
bool chk = 1;
rep (i, 1, n) {
if (t[i].size () > 1) chk = 0;
}
if (chk) {
cout << T << endl;
rrp (i, 1, T) {
init ();
rep (j, 2, n) {
if ((dep[id[j]] & 1) == (i & 1)) col[id[j]] = col[fa[id[j]]];
}
put ();
} return 0;
}
int q = 0, p = 0;
rep (i, 1, n) {
if (t[i].size () > 1) {
if (dep[q] < dep[i]) q = i, p = fa[i];
}
}
int u = t[q][0];
for (auto v : t[q]) if (! e[v][p]) u = v;
memset (vis, 0, sizeof vis);
if (! t[u].empty ()) {
int v = u;
while (! t[v].empty ()) v = t[v][0], vis[v] = 1;
}
G[u].eb (q);
G[q] = t[q];
if (p) G[q].eb (p);
tot = 0; fa[u] = 0;
dep[u] = 0; dfs (u);
if (! t[u].empty ()) {
int v = u;
while (! t[v].empty ()) dep[t[v][0]] = dep[v] + 1, v = t[v][0], id[++ tot] = v;
}
cout << T << endl;
rrp (i, 1, T) {
init ();
if ((i % 3) <= 1) col[q] = col[u];
rep (j, 3, n) {
if (((fa[id[j]] == u) ? 2 : (dep[id[j]] & 1)) == (i % 3)) col[id[j]] = col[fa[id[j]]];
}
put ();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?