(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("
");
        if (next == tot) break;
        now = next + 1;
    }
    for (++i; i <= k; ++i) puts("0");

}
原文地址:https://www.cnblogs.com/waryan/p/14026901.html