正在载入在线练习界面,本页内容可直接阅读…

AK CSP › CSP-S 2023 第一轮真题 › 第34题

CSP-S 2023 第一轮 第34题:完善程序(第 19 题)第 1 空

完善程序 · 图论算法 · 答案 B

题目

(第 $k$ 小路径)给定一张 $n$ 个点 $m$ 条边的有向无环图,定点编号从 $0$ 到 $n-1$,对于一条路径,我们定义“路径序列”为该路径从起点出发依次经过的顶点编号构成的序列。求所有至少包含一个点的简单路径中,“路径序列”字典序第 $k$ 小的路径。保证存在至少 $k$ 条路径。上述参数满足 $1 \le n,m \le 10^5, 1 \le k \le 10^{18}$。

在程序中,我们求出从每个点出发的路径数量。超过 $10^{18}$ 的数都用 $10^{18}$ 表示。然后我们根据 $k$ 的值和每个顶点的路径数量,确定路径的起点,然后可以类似地依次求出路径中的每个点。

试补全程序。

#include <iostream>
#include <algorithm>
#include <vector>

const int MAXN = 100000;
const long long LIM = 1000000000000000000ll;

int n, m, deg[MAXN];
std::vector<int> E[MAXN];
long long k, f[MAXN];

int next(std::vector<int> cand, long long &k) {
    std::sort(cand.begin(), cand.end());
    for (int u : cand) {
        if (①) return u;
        k -= f[u];
    }
    return -1;
}

int main() {
    std::cin >> n >> m >> k;
    for (int i = 0; i < m; ++i) {
        int u, v;
        std::cin >> u >> v; // 一条从u到v的边
        E[u].push_back(v);
        ++deg[v];
    }
    std::vector<int> Q;
    for (int i = 0; i < n; ++i)
        if (!deg[i]) Q.push_back(i);
    for (int i = 0; i < n; ++i) {
        int u = Q[i];
        for (int v : E[u]) {
            if (②)
                Q.push_back(v);
            --deg[v];
        }
    }
    std::reverse(Q.begin(), Q.end());
    for (int u : Q) {
        f[u] = 1;
        for (int v : E[u])
            f[u] = ③;
    }
    int u = next(Q, k);
    std::cout << u << std::endl;
    while (④) {
        ⑤;
        u = next(E[u], k);
        std::cout << u << std::endl;
    }
    return 0;
}

本小题

①处应填()

选项

  • A. k >= f[u]
  • B. k <= f[u]
  • C. k > f[u]
  • D. k < f[u]

答案

B

题解

应选 B:k <= f[u]。

f[u] 表示从顶点 u 出发的路径数量。将候选顶点按编号从小到大排序后,以同一个顶点开头的路径在字典序中构成连续的一组。

寻找第 k 小的路径时:

  • 如果 k <= f[u],目标就在当前这一组中,返回 u。
  • 如果 k > f[u],跳过这一组,并用 k -= f[u] 更新目标在剩余路径中的排名。

例如,当前顶点对应的组有 3 条路径:当 k = 3 时,目标仍在这一组中,所以必须包含等号。

真题版权归 CCF 所有,本站仅用于非商业教学用途。页面加载后可直接在线作答,作答记录保存在本浏览器或账号中。 京ICP备2026056990号-1 京公网安备11010502062986号