QOJ.ac

QOJ

Type: Editorial

Status: Open

Posted by: jiangly

Posted at: 2025-12-13 00:39:33

Last updated: 2025-12-13 00:39:41

Back to Problem

题解

题意

给定一张 $n$ ($2\le n\le 2000$) 个点的竞赛图,找到从每个点开始的经过点数最多的简单路径。

题解

众所周知 $\ge 3$ 个点的强连通竞赛图有哈密顿回路,因此从 $u$ 开始最长的路径就是拓扑序在 $u$ 所属的强连通分量之后 (包括其本身) 的强连通分量的哈密顿路径相连。在每个强连通分量找到哈密顿回路即可。找哈密顿回路时,首先找到一条哈密顿路径 (按任意顺序加点即可),然后找到路径上第一个向第一个点有边的点,作为初始的环。之后每次找到第一个向环中点有边的点,将它及之前未加入的点加入即可。

时间复杂度:$O(n^2)$。

代码

#include <iostream>
#include <vector>
#include <algorithm>
int n;
std::vector<std::vector<bool>> g;
int cntScc, dfsClock;
std::vector<int> dfn, low, belong;
std::vector<int> stk;
std::vector<std::vector<int>> ans;
std::vector<std::vector<int>> h;
void tarjan(int u) {
    dfn[u] = low[u] = dfsClock++;
    stk.push_back(u);
    for (int v = 0; v < n; ++v) {
        if (g[u][v]) {
            if (dfn[v] == -1) {
                tarjan(v);
                low[u] = std::min(low[u], low[v]);
            } else if (belong[v] == -1) {
                low[u] = std::min(low[u], dfn[v]);
            }
        }
    }
    if (dfn[u] == low[u]) {
        int v;
        do {
            v = stk.back();
            belong[v] = cntScc;
            stk.pop_back();
        } while (v != u);
        ++cntScc;
    }
}
auto solve(std::vector<int> v) {
    if (int(v.size()) == 1)
        return v;
    std::vector<int> h;
    for (auto u : v)
        h.insert(std::find_if(h.begin(), h.end(), [&](int v) {return g[u][v];}), u);
    auto it = std::find_if(h.begin(), h.end(), [&](int v) {return g[v][h[0]];}) + 1;
    std::vector<int> c(h.begin(), it);
    while (it != h.end()) {
        auto r = it;
        while (std::find_if(c.begin(), c.end(), [&](int v) {return g[*r][v];}) == c.end())
            ++r;
        auto p = c.begin();
        while (p + 1 != c.end() && !(g[*p][*it] && g[*r][*(p + 1)]))
            ++p;
        c.insert(p == c.end() ? c.begin() : p + 1, it, r + 1);
        it = r + 1;
    }
    return c;
}
int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cin >> n;
    g.assign(n, std::vector<bool>(n));
    dfn.assign(n, -1);
    low.resize(n);
    belong.assign(n, -1);
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < i; ++j) {
            int x;
            std::cin >> x;
            g[i][j] = x ^ 1;
            g[j][i] = x;
        }
    }
    for (int i = 0; i < n; ++i)
        if (dfn[i] == -1)
            tarjan(i);
    h.resize(cntScc);
    ans.resize(n);
    for (int i = 0; i < n; ++i)
        h[belong[i]].push_back(i);
    for (int i = 0; i < cntScc; ++i) {
        h[i] = solve(h[i]);
        for (auto it = h[i].begin(); it != h[i].end(); ++it) {
            int u = *it;
            ans[u].insert(ans[u].end(), it, h[i].end());
            ans[u].insert(ans[u].end(), h[i].begin(), it);
            for (int j = i - 1; j >= 0; --j)
                ans[u].insert(ans[u].end(), h[j].begin(), h[j].end());
        }
    }
    for (int i = 0; i < n; ++i) {
        std::cout << ans[i].size();
        for (int u : ans[i])
            std::cout << " " << u + 1;
        std::cout << "\n";
    }
    return 0;
}

Comments

No comments yet.