hdu 4857 逃生(拓扑排序逆序 + 优先队列)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4857

题意:有编号 1 ~ n 的 n 个人逃生,编号越小的人越有钱, 在满足 m 个前提的条件下要尽可能早的逃脱 。m个前提,对于每个前提 a , b,代表 a 要早于 b逃脱。

思路:

(1)这题可以理解为有钱的人优先级越高,所以可以用优先队列。

(2)但是要注意这道题和字典序升序的区别。

  eg:5 1

    5 1

  按照字典序的答案:2 3 4 5 1,    本题答案: 5 1 2 3 4。

  因为 1 最有钱, 所以他会使自己尽可能早的出去。

(3)需要用拓扑排序反序。

  如上一个例子, 当正序拓扑排序时,想让编号小的优先级高,但是因为 5 需要在 1 之前出去, 因为 5 的优先级太低, 导致 1 的位置过于靠后, 很明显不符合题意。

  而当逆序时,使 5 -> 1的有向边, 改为 1 -> 5,可以理解为 1需要在 5 的后面出去, 使逃生序列从后往前生成,这时,编号大的反而优先级高,理解为 编号大的要尽可能最后走。 这样生成的序列反向输出即可。 在这种情况下 1 的低优先级会带着 5 到序列末尾:4 3 2 1 5, 反序输出就是答案5 1 2 3 4。

#include <stdio.h>
#include <queue>
#include <math.h>
#include <string.h>
#include <algorithm>
using namespace std;

const int N = 30007;

typedef struct Edge
{
    int to;
    int next;
}edge;
Edge eg[N * 4];

typedef struct Node
{
    int num;
    friend bool operator <(Node a, Node b)
    {
        return a.num < b.num;
    }
}node;
node nd[N];

int seq[N], isVis[N], head[N], in[N], out[N], t, n, m, cnt_seq;
priority_queue <node> q;

void toposort()
{
    cnt_seq = 0;
    while (!q.empty())
        q.pop();
    for (int i = 1; i <= n; i++)
    {
        if (in[i] == 0)
        {
            node temp;
            temp.num = i;
            q.push(temp);
            isVis[i] = 1;
        }
    }
    while (!q.empty())
    {
        node temp = q.top();
        q.pop();
        seq[cnt_seq++] = temp.num;
        int r = head[temp.num];
        while (r != -1)
        {
            in[eg[r].to]--;
            if (in[eg[r].to] == 0 && !isVis[eg[r].to])
            {
                node nextNode;
                nextNode.num = eg[r].to;
                q.push(nextNode);
                isVis[eg[r].to] = 1;
            }
            r = eg[r].next;
        }
    }
}

int main()
{
    while (scanf("%d", &t) != EOF)
    {
        while (t--)
        {
            memset(in, 0, sizeof(in));
            memset(out, 0 ,sizeof(out));
            memset(head, -1, sizeof(head));
            memset(isVis, 0, sizeof(isVis));
            scanf("%d%d", &n, &m);
            for (int i = 1; i <= m; i++)
            {
                int u, v;
                scanf("%d%d", &v, &u);
                eg[i].to = v;
                eg[i].next = head[u];
                in[v]++;
                out[u]++;
                head[u] = i;
            }
            toposort();
            for (int i = cnt_seq - 1; i >= 0; i--)
                printf("%d%c", seq[i], i == 0 ? ‘\n‘ : ‘ ‘);
        }
    }
    return 0;
}
时间: 2024-10-16 19:38:55

hdu 4857 逃生(拓扑排序逆序 + 优先队列)的相关文章

hdu 4857 逃生 拓扑排序+优先队列,逆向处理

hdu4857 逃生 题目是求拓扑排序,但不是按照字典序最小输出,而是要使较小的数排在最前面. 一开始的错误思路:给每个点确定一个优先级(该点所能到达的最小的点),然后用拓扑排序+优先对列正向处理,正向输出.这是错误的,如下样例: 1 5 4 5 2 4 3 2 1 3 1 正确的解法:是反向建边,点大的优先级高,用拓扑排序+优先队列,逆向输出序列即可. 根据每对限制,可确定拓扑序列,但此时的拓扑序列可能有多个(没有之间关系的点的顺序不定).本题要求较小的点排到前面,则可确定序列. (1)如果点

hdu 4857 逃生 拓扑排序+PQ,剥层分析

pid=4857">hdu4857 逃生 题目是求拓扑排序,但不是依照字典序最小输出,而是要使较小的数排在最前面. 一開始的错误思路:给每一个点确定一个优先级(该点所能到达的最小的点).然后用拓扑排序+优先对列正向处理,正向输出.这是错误的.例如以下例子: 1 5 4 5 2 4 3 2 1 3 1 正确的解法:是反向建边.点大的优先级高,用拓扑排序+优先队列,逆向输出序列就可以. 依据每对限制,可确定拓扑序列,但此时的拓扑序列可能有多个(没有之间关系的点的顺序不定).本题要求较小的点排到

HDU 4857 逃生 拓扑排序好题 第一次做CLJ出的题

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

hdu 4857 逃生 拓扑排序+逆向建图

逃生 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Description 糟糕的事情发生啦,现在大家都忙着逃命.但是逃命的通道很窄,大家只能排成一行. 现在有n个人,从1标号到n.同时有一些奇怪的约束条件,每个都形如:a必须在b之前.同时,社会是不平等的,这些人有的穷有的富.1号最富,2号第二富,以此类推.有钱人就贿赂负责人,所以他们有一些好处. 负责人现在

hdu 4857 逃生 (拓扑排序+保证最小在前面)

逃生 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 74    Accepted Submission(s): 13 Problem Description 糟糕的事情发生啦,现在大家都忙着逃命.但是逃命的通道很窄,大家只能排成一行. 现在有n个人,从1标号到n.同时有一些奇怪的约束条件,每个都形如:a必须在b之前. 同时,社会是不平

HDU 4857 逃生 (优先队列+反向拓扑)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4857 解题报告:有n个点,有m个条件限制,限制是像这样的,输入a  b,表示a必须排在b的前面,如果不能确定两个数谁排在前面则尽量把小的排在前面. 首先把出度为0的点加入到优先队列中,然后每次用优先队列中弹出的点去更新其它点的出度,更新的同时如果又有其它点的出度为0的话又加到优先队列中, 最后按照从优先队列中出队的反序输出就可以了.我还是不懂为什么按照入度为0然后加入到优先队列然后正序输出这样为什么

HDU 4917 Permutation 拓扑排序的计数

题意: 一个有n个数的排列,给你一些位置上数字的大小关系.求合法的排列有多少种. 思路: 数字的大小关系可以看做是一条有向边,这样以每个位置当点,就可以把整个排列当做一张有向图.而且题目保证有解,所以只一张有向无环图.这样子,我们就可以把排列计数的问题转化为一个图的拓扑排序计数问题. 拓扑排序的做法可以参见ZJU1346 . 因为题目中点的数量比较多,所以无法直接用状压DP. 但是题目中的边数较少,所以不是联通的,而一个连通块的点不超过21个,而且不同连通块之间可以看做相互独立的.所以我们可以对

hdu 2647 Reward (拓扑排序分层)

Reward Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3815    Accepted Submission(s): 1162 Problem Description Dandelion's uncle is a boss of a factory. As the spring festival is coming , he wa

hdu 4857 逃生 (拓扑排序+优先队列)

逃生 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 688    Accepted Submission(s): 190 Problem Description 糟糕的事情发生啦,现在大家都忙着逃命.但是逃命的通道很窄,大家只能排成一行. 现在有n个人,从1标号到n.同时有一些奇怪的约束条件,每个都形如:a必须在b之前.同时,社会是不平