题目链接: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