accoders NOI #5011. 小j 的组合 题解

哈密顿回路需要把每个点经过且只经过一遍,而在树上,这只能是一条链。

手推一下可以发现,操作相当于把每个点复制一遍,等同于给允许这个点多经过一次,有了这个结论就容易了许多。

在树上 DFS,每次返回到父亲就操作一次,但这样不能保证操作最少(当然,最后不需要回到根节点)。

不需要返回的点构成了一条链,剩下的每个点都需要返回操作一次,那么显然当这条链最长也就是直径的时候,操作次数最少。

直接找出直径模拟即可。

// D. 小j 的组合
#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
int dis[105][105], n, num;
bool vis[105];
vector<int> ans;
namespace FASTIO {
inline int read() {
    int res = 0, f = 1;
    char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (isdigit(ch)) {
        res = res * 10 + ch - '0';
        ch = getchar();
    }
    return res * f;
}
inline void write(int x) {
    int top = 0;
    char s[25];
    do {
        s[++top] = x % 10 + '0';
        x /= 10;
    } while (x);
    while (top) putchar(s[top--]);
    return;
}
}  // namespace FASTIO
using namespace FASTIO;
namespace GRAPH {
inline void floyd() {
    for (register int k = 1; k <= n; k++)
        for (register int i = 1; i <= n; i++)
            for (register int j = 1; j <= n; j++) dis[i][j] = min(dis[i][j], dis[j][k] + dis[i][k]);
    return;
}
void DFS(const int &k, const int &t) {
    int v = 0;
    ans.emplace_back(k);
    vis[k] = true;
    for (register int i = 1; i <= n; i++) {
        if (!vis[i] && dis[k][i] == 1) {
            if (dis[t][k] == dis[t][i] + 1) {
                v = i;
                continue;
            }
            DFS(i, t);
            write(k);
            putchar(' ');
            ans.emplace_back(++num);
        }
    }
    if (v)
        DFS(v, t);
    return;
}
}  // namespace GRAPH
using namespace GRAPH;
int main() {
    freopen("combo.in", "r", stdin);
    freopen("combo.out", "w", stdout);
    int u, v, s, t;
    n = read();
    for (register int i = 1; i <= n; i++) {
        for (register int j = 1; j <= n; j++) {
            if (i == j)
                dis[i][j] = 0;
            else
                dis[i][j] = 114514;
        }
    }
    for (register int i = 1; i < n; i++) {
        u = read();
        v = read();
        dis[u][v] = dis[v][u] = 1;
    }
    floyd();
    s = t = 1;
    for (register int i = 1; i <= n; i++) {
        for (register int j = 1; j <= n; j++) {
            if (dis[i][j] > dis[s][t]) {
                s = i;
                t = j;
            }
        }
    }
    /*cout<<"fuck\n";
    exit(0);*/
    write(n - dis[s][t] - 1);
    putchar('\n');
    num = n;
    DFS(s, t);
    putchar('\n');
    for (int u : ans) {
        write(u);
        putchar(' ');
    }
    putchar('\n');
    fclose(stdin);
    fclose(stdout);
    return 0;
}
/*
 * accoders NOI-2022NOIP A层联测11
 * http://47.92.197.167:5283/contest/266/problem/4
 * -DONLINE_JUDGE -O2 -std=c++11
 * 2022.10.18
 */
posted @ 2022-10-18 20:24  Day_Dreamer_D  阅读(131)  评论(0)    收藏  举报