逃生(hdu4857)题解

Description

糟糕的事情发生啦,现在大家都忙着逃命。但是逃命的通道很窄,大家只能排成一行。
现在有n个人,从1标号到n。同时有一些奇怪的约束条件,每个都形如:a必须在b之前。
同时,社会是不平等的,这些人有的穷有的富。1号最富,2号第二富,以此类推。有钱人就贿赂负责人,所以他们有一些好处。
负责人现在可以安排大家排队的顺序,由于收了好处,所以他要让1号尽量靠前,如果此时还有多种情况,就再让2号尽量靠前,如果还有多种情况,就让3号尽量靠前,以此类推。
那么你就要安排大家的顺序。我们保证一定有解.
注:本题含有SPJ,输出任意一种解即可,无需保证字典序最小

Input

第一行一个整数T(1 <= T <= 5),表示测试数据的个数。
然后对于每个测试数据,第一行有两个整数n(1 <= n <= 30000)和m(1 <= m <= 100000),分别表示人数和约束的个数。
然后m行,每行两个整数a和b,表示有一个约束a号必须在b号之前。a和b必然不同。

Output

对每个测试数据,输出一行排队的顺序,用空格隔开。

Sample Input

1
5 10
3 5
1 4
2 5
1 2
3 4
1 4
2 3
1 5
3 5
1 2

 Sample Output

    1 2 3 4 5

    为了解决这个问题,我们需要在满足所有约束条件的情况下,使得编号较小的节点尽可能靠前排列。这个问题可以通过拓扑排序结合优先队列(最小堆)来解决,以确保每次处理入度为0的最小节点。

    方法思路

    1. 输入处理与初始化:读取输入的测试用例,初始化邻接表和入度数组,并使用集合来去重边。

    2. 构建邻接表和入度数组:处理每条边,确保每条边只处理一次,避免重复计算入度。

    3. 拓扑排序:使用优先队列(最小堆)来选择当前入度为0的最小节点进行处理,维护拓扑顺序。

    4. 输出结果:将拓扑排序的结果输出。

    解决代码

    #include 
    #define int long long
    using namespace std;
    
    signed main() {
        int T;
        cin >> T;
        while (T --) {
            int n, m;
            cin >> n >> m;
            vector > adj(n + 1);
            vector in_degree(n + 1, 0);
            unordered_set edges;
            for (int i = 0; i < m; ++i) {
                int a, b;
                cin >> a >> b;
                long long edge_id = (long long)a * (n + 1) + b;
                if (edges.find(edge_id) == edges.end()) {
                    adj[a].push_back(b);
                    in_degree[b]++;
                    edges.insert(edge_id);
                }
            }
    
            priority_queue, greater> q;
            for (int i = 1; i <= n; ++i) {
                if (in_degree[i] == 0) {
                    q.push(i);
                }
            }
            vector res;
            while (!q.empty()) {
                int u = q.top();
                q.pop();
                res.push_back(u);
                for (int v : adj[u]) {
                    if (--in_degree[v] == 0) {
                        q.push(v);
                    }
                }
            }
            for (size_t i = 0; i < res.size(); ++i) {
                printf("%d%c", res[i], " \n"[i == res.size() - 1]);
            }
        }
        return 0;
    }

    代码解释

    1. 输入处理:使用scanf读取输入数据以提高效率,处理多个测试用例。

    2. 邻接表和入度数组:使用邻接表存储图的边,入度数组记录每个节点的入度,使用集合去重边以避免重复计算入度。

    3. 优先队列:使用最小堆优先处理入度为0的最小节点,确保较小的节点尽可能靠前。

    4. 拓扑排序:每次从优先队列中取出最小节点处理,并更新其邻接节点的入度,将新的入度为0的节点加入队列。

    5. 输出结果:将拓扑排序的结果按顺序输出。

    你可能感兴趣的:(题解,c++)