码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2016-08-04 19:25:56      阅读:155      评论:0      收藏:0      [点我收藏+]

标签:

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

 

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

标签:

原文地址:http://www.cnblogs.com/burning-flame/p/5737782.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!