(NC213863)牛客小白月赛29J.克隆(欧拉序)
题意
给你n个点m条边的无向连通图。并且给你k个分身。每个分身在一个晚上只能经过\((2 * n - k - 1) / k\)个点,并且经过的相邻的两点之间必须有连边(这些点可以重复)。想知道存不存在一种方案使得每个点至少被一个分身经过。
思路
根据\(2*n\)和只能经过相邻的点的提示,我们想到欧拉序,在欧拉序上走必然是可以经过每个点的。
然后我们考虑分身放在哪些点。显然我们以最大步长去枚举即可,多出来的分身都走0个点就好了。
欧拉序
在\(dfs\)序的基础上走过的点也还继续走,一笔连着走。
9 8
1 -> 2 , 1 -> 7 , 1 -> 4, 2 -> 8, 2 -> 5, 4 -> 3, 4 -> 6, 3 -> 9的图的欧拉序为:
1 2 8 2 5 2 1 7 1 4 3 9 3 4 6 4 1,和dfs序相似的,欧拉序也不唯一。
欧拉序的长度是 \(n + m = 2 *n - 1\)
#include<bits/stdc++.h>
using namespace std;
//#define int long long
const int maxn = 1e5 + 10;
vector<int>edge[maxn];
int pos[maxn << 1], tot;
bool vis[maxn];
void dfs(int u, int fa) {
vis[u] = true;
pos[++tot] = u;
for(int i = 0; i < edge[u].size(); ++i) {
int v = edge[u][i];
if(vis[v]) continue;
dfs(v, u);
pos[++tot] = u;
}
}
signed main() {
int n, m, k; cin >> n >> m >> k;
for (int l = 1; l <= m; ++l) {
int u, v; cin >> u >> v;
edge[u].push_back(v);
edge[v].push_back(u);
}
dfs(1, 0);
puts("YES");
int step = (2 * n + k - 1) / k;
int now = 1, i;
for (i = 1; i <= k; ++i) {
int next = min(now + step - 1, tot);
int p = next - now + 1;
printf("%d ", p);
for (int j = 0; j < p; ++j) {
if (j) printf(" %d", pos[now + j]);
else printf("%d", pos[now + j]);
}
printf("\n");
if (next == tot) break;
now = next + 1;
}
for (++i; i <= k; ++i) puts("0");
}