题意:有N个人,M个优先级a,b表示a优先于b。而且每一个人有个编号的优先级。输出顺序。

思路来自:与PKU3687一样

在主要的拓扑排序的基础上又添加了一个要求:编号最小的节点要尽量排在前面;在满足上一个条件的基础上,编号第二小的节点要尽量排在前面;在满足前两个条件的基础上,编号第三小的节点要尽量排在前面……依此类推。(注意,这和字典序是两回事,不能够混淆。

如图 1 所看到的,满足要求的拓扑序应该是:6 4 1 3 9 2 5 7 8 0。





图 1 一个拓扑排序的样例

一般来说。在一个有向无环图中,用 BFS 进行拓扑排序是比較常见的做法,如算法 1 所看到的。

可是它不一定能得到本题要求的拓扑序。

1. 把全部入度为 0 的节点放进队列 Q

2. WHILE: Q 不是空队列

3.     从 Q 中取出队列首元素 a,把 a 加入到答案的尾部

4.     FOR:全部从 a 出发的边 a → b

5.         把 b 的入度减 1。

假设 b 的入度变为 0,则把 b 放进队列 Q。

算法 1 用 BFS 进行拓扑排序

为了解决本问题。以下让我来探究一下拓扑序的一些性质。以图 1 为例,节点 0 毫无疑问排在最后。除了节点 0 以外,有三条互相平行的路径:6 → 4 → 1、 3 → 9 → 2 和 5 → 7 → 8

一条路径上的各个节点的先后关系都是不能改变的,比方路径 6 → 4 → 1 上的三个节点在拓扑序中,一定是 6 在最前,1 在最后。

可是,互相平行的各条路径,在总的拓扑序中随意交错都是合法的。比方。以下都是图 1 的合法拓扑序:

6 4 1 3 9 2 5 7 8 0、 3 6 9 4 5 1 7 8 2 0、 5 6 4 7 3 8 1 9 2 0、 3 5 6 4 1 7 9 2 8 0、 6 5 7 8 4 3 9 2 1 0。

怎么才干找出题目要求的拓扑序呢?在这里,我想用字典序最先的拓扑序来引出这个算法。

算法 2 能够求出字典序最先的拓扑序。

1. 把全部入度为 0 的节点放进优先队列 PQ

2. WHILE: PQ 不是空队列

3.     从 PQ 中取出编号最小的元素 a。把 a 加入到答案的尾部

4.     FOR:全部从 a 出发的边 a → b

5.        把 b 的入度减 1。假设 b 的入度变为 0,则把 b 放进优先队列PQ。

算法 2 求出字典序最先的拓扑序

可见,算法 2 和算法 1 基本一样,仅仅是把队列改成了优先队列。用它求出的图 1 的字典序最先的拓扑序为:3 5 6 4 1 7 8 9 2 0。可是这显然不是本题要求的答案,由于节点 1 的位置还不够靠前。

算法 2 能够算是一个贪心算法,每一步都找编号最小的节点。可是对于图 1 中的三条路径,头的编号比較小的。不一定要先出队列。正确的步骤应该例如以下:

  1. 节点 0 的位置是铁定在最后的,不用考虑。仅仅考虑剩下的三条路径。
  2. 先找编号最小的。节点 1。把它和它所在的路径中位于它前面的节点所有拿出来。眼下的答案是 6 4 1,这样。 节点 1 就尽量靠前了。
  3. 再找剩下的节点中编号最小的,节点 2。把它和它所在的路径中位于它前面的节点所有拿出来。眼下的答案是 6 4 1 3 9 2 ,这样,节点 2 就尽量靠前了。

  4. 仅仅剩下一条路径了,仅仅能依次把当中的节点拿出来。最后答案就是 6 4 1 3 9 2 5 7 8 0。

显然,算法 2 的贪心策略对于这个问题是不可行的。不能着眼于每条路径的头,而是要找编号最小的节点在哪条路径上,优先把这条路径拿出来。但问题在于,在 BFS 的过程中,我们仅仅能看到每条路径的头,看不到后面的节点。这该怎么办呢?

让我们换个角度想一想,节点 3 和 6。应该是 6 先出队列,由于节点 1 在 6 的后面。这和节点 3 和 6 的编号大小没有不论什么关系。

可是。再看另外两条路径的尾部,节点 2 和 8,能够肯定地说,2 一定先出队列,由于它们后面都没有别的节点了。这个时候全然以这两个节点本身的编号大小决定顺序。归纳起来就是说,对于若干条平行的路径,小的头部不一定排在前面。可是大的尾部一定排在后面。于是,就有了算法 3。

1. 把全部出度为 0 的节点放进优先队列 PQ

2. WHILE: PQ 不是空队列

3.     从 PQ 中取出编号最大的元素 a。把 a 加入到答案的头部。

4.     FOR:全部指向 a 的边 b → a

5.        把 b 的出度减 1。假设 b 的出度变为 0。则把 b 放进优先队列PQ。

算法 3 求出本题目要求的拓扑序

#include<cstdio>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<map>
#include<cmath>
#include<iostream>
#include <queue>
#include <stack>
#include<algorithm>
#include<set>
using namespace std;
#define INF 1e8
#define eps 1e-8
#define LL long long
#define maxn 505
#define mod 1000000007
vector<int>G[30003];
int out[30003];
int n,m,a[30003];
void toposort()
{
priority_queue<int>q;
int len=n;
for(int i=1;i<=n;i++)
if(out[i]==0)
q.push(i);
while(!q.empty())
{
int tmp=q.top();
a[len--]=tmp;
q.pop();
for(int i=0;i<G[tmp].size();i++)
{
out[G[tmp][i]]--;
if(out[G[tmp][i]]==0)
q.push(G[tmp][i]);
}
}
for(int i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\n",a[n]);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
int a,b;
for(int i=1;i<=n;i++)
out[i]=0,G[i].clear();
while(m--)
{
scanf("%d%d",&a,&b);
G[b].push_back(a);
out[a]++;
}
toposort();
}
return 0;
}
/*
1
5 10
3 5
1 4
2 5
1 2
3 4
1 4
2 3
1 5
3 5
1 2
*/

HDU 4857 (反向拓扑排序 + 优先队列)的更多相关文章

  1. HDU-4857-逃生-反向拓扑排序+优先队列

    HDU-4857 题意就是做一个符合条件的排序,用到拓扑序列. 我一开始wa了多发,才发现有几个样例过不了,发现1->2->3...的顺序无法保证. 后来就想用并查集强连,还是wa: 后来 ...

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

    pid=4857">hdu4857 逃生 题目是求拓扑排序,但不是依照字典序最小输出,而是要使较小的数排在最前面. 一開始的错误思路:给每一个点确定一个优先级(该点所能到达的最小的点) ...

  3. HDU 4857 逃生(反向拓扑排序+优先队列)

    ( ̄▽ ̄)" //这题对序号输出有要求,较小的序号优先输出,所以用到优先队列 //优先队列是优先弹出值最大的,所以最后要反向输出结果,才是正确的output #include<iost ...

  4. hdu 4857 逆向拓扑排序+反向输出

    /*一组测试实例 4 4 2 3 1 2 4 */ #include<stdio.h> #include<string.h> #include<queue> usi ...

  5. HDU 5638 Toposort 拓扑排序 优先队列

    Toposort 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5638 Description There is a directed acycli ...

  6. hdu 4857 反向拓扑问题

    尤其要注意拓扑的分层问题 不难理解 就是不怎么好想到 拓扑的思路这里就不累述了 #include <iostream> #include <cstdio> #include & ...

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

    逃生 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Descr ...

  8. hdu 2647 Reward(拓扑排序+优先队列)

    Problem Description Dandelion's uncle is a boss of a factory. As the spring festival is coming , he ...

  9. HDU 4857 拓扑排序 优先队列

    n个数,已经有大小关系,现给m个约束,规定a在b之前,剩下的数要尽可能往前移.输出序列 大小关系显然使用拓扑结构,关键在于n个数本身就有大小关系,那么考虑反向建图,优先选择值最大的入度为零的点,这样得 ...

随机推荐

  1. debian支持ll命令

    debian支持ll命令 $ ll -bash: ll: command not found 没有ll这个命令.尽管也知道ll事实上 是ls -l 这个命令的别名,可是总感觉不是非常习惯.由于之前一直 ...

  2. Android学习笔记之View(一):LayoutInflater

    使用LayoutInflater加载布局的两种方式: 第一种: LayoutInflater inflater=LayoutInflater.from(context); inflater.infla ...

  3. 网页制作之JavaScript部分 2 - DOM操作

    1.DOM的基本概念  htmlDOM是一种面向对象的树的模型,它包含html中的所有元素:通过html可以找到所有包含在dom中的元素. DOM是文档对象模型,这种模型为树模型:文档是指标签文档:对 ...

  4. 个人mysql配置命令

    Microsoft Windows [版本 6.1.7601]版权所有 (c) 2009 Microsoft Corporation.保留所有权利. C:\Windows\system32>cd ...

  5. C# 使用IENUMERABLE,YIELD

    C# 使用IENUMERABLE,YIELD 前言 在上篇文章中我得出结论,遍历迭代器修改迭代器中项目的值未生效,是因为使用了yield return,并且每次遍历迭代器都执行返回迭代器的方法.这篇文 ...

  6. Mysql主从配置+读写分离(转)

       MySQL从5.5版本开始,通过./configure进行编译配置方式已经被取消,取而代之的是cmake工具.因此,我们首先要在系统中源码编译安装cmake工具. 注:安装前须查看是否已经安装了 ...

  7. api 跳转规则

    api 配置: <Context docBase="zjzc-web-api" path="/api" reloadable="false&qu ...

  8. mysql数据导出权限问题

    mysql数据导出的方法有非常多,比如mysqldump, mysql -e 'sql' > file, 这些都能够非常方便的导出数据,但是在使用普通用户导出数据的时候,出现了问题. 1 sel ...

  9. HDU 1593 find a way to escape

    数学题. 题意是问你能不能逃脱. 当V1的 角速度大于 V2的时候,能够一直保持 V1,O(圆心),V2 三点一线. 跑到一定距离.角速度小于的时候,就以三点一线为初始状态直接跑直线. #includ ...

  10. 用xerces-c来进行xml schema校验

    在xerces-c的官方站点上有文章指引说明是怎样进行xml schema校验. http://xerces.apache.org/xerces-c/schema-3.html 给出的样例代码: // ...