HDU 4857 逃生 【拓扑排序+反向建图+优先队列】
逃生
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 6686 Accepted Submission(s): 1958
Problem Description
糟糕的事情发生啦,现在大家都忙着逃命。但是逃命的通道很窄,大家只能排成一行。
现在有n个人,从1标号到n。同时有一些奇怪的约束条件,每个都形如:a必须在b之前。
同时,社会是不平等的,这些人有的穷有的富。1号最富,2号第二富,以此类推。有钱人就贿赂负责人,所以他们有一些好处。
负责人现在可以安排大家排队的顺序,由于收了好处,所以他要让1号尽量靠前,如果此时还有多种情况,就再让2号尽量靠前,如果还有多种情况,就让3号尽量靠前,以此类推。
那么你就要安排大家的顺序。我们保证一定有解。
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
Author
CLJ
【题意】:有N个人,M个优先级a,b表示a优先于b,并且每个人有个编号的优先级,输出顺序。
拓扑排序,因为需要尽可能让编号较小的在前面,比如有如下约束
1->4->2 5->3->2
如果我们考虑正向建图的话得出的拓扑序列为 1 4 5 3 2
但是实际上,在图中 1 4 与 5 3 之间并没有约束,并且负责人在排序的时候会先去考虑 3 号的位置,于是有另一种结果 1 5 3 4 2 。
可见,第二种结果才是正确的,因为较小的编号总是优先选择靠前。
因为正向建图求拓扑序列的过程中,编号较小的点可能会被更大的点挡住,于是我们采用逆向建图的方法,然后用大顶堆维护,把编号较大的点先选出来,最后反转数组即可。
题意大抽象后概是这样的:给定一个有向图,将其按线性优先级输出。题目大致一扫,可以明白是个赤果果的拓扑排序。以前学过一点拓扑排序,后来给忘掉
了。拓扑排序就是解决对有向图的点进行线性排序的相关问题。假设给定一标记优先级的有向图,那么每个有向边通向的点的入度都要+1,这样的标记后,入度为
0的点就可以看成是优先级最高的点(因为没有点在它前面去连接它)。把此点取出,与这个点相连的其他点的边也就全部都要消掉了,同时将它们的入度减去1;
这样会产生新的入度为0的点,那么这个点就是剩下的点中的优先级最高的点,重复上述的更新过程即可。此题有坑,可能会有多个拓扑环;还有此题要求输出的点
如果没有拓扑关系则按照小编号在前的方式排列。看到这个条件第一反应是在取优先级高的点的过程中用优先队列去写,先出队列的就是编号较小的,这么想似乎没
错。但是后来debug了下,假如有一有向图关系是这样的:6->3->1;5->4->2;这样的话按照最小堆来进行拓扑排序会出这样的结果:5 4 2 6 3 1;但是实际上
我们可以把6 3 1 这个拓扑环放在前面,生成6 3 1 5 4 2这样的线性序列。究其原因,我们优先队列先弹出的是编号较小的符合条件的点,但实际上这个点只能算
是该拓扑环排序后的头结点,我们想要保证让小号的全部尽可能地放在前面,我们需要保证拓扑环的尾部的小号也在前面。这样来想一下可以发现先出编号小的是
不完善的。于是我们可以考虑逆向思维,先弹出序号大的,那么这样先出队列的就是编号最大的;但是我们有需要编号最大的在最后输出,换句话说就是编号最大的
是作为优先级最低的;那么我们把有向图也给逆向储存,这样按优先级条件弹出的顺序才会一致(优先弹出优先级最低的)。大致思路明白后代码实现就很简单了。
#include<cstdio>
#include<string>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<cstring>
#include<set>
#include<queue>
#include<algorithm>
#include<vector>
#include<map>
#include<cctype>
#include<stack>
#include<sstream>
#include<list>
#include<assert.h>
#include<bitset>
#include<numeric>
#define debug() puts("++++")
#define gcd(a,b) __gcd(a,b)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define fi first
#define se second
#define pb push_back
#define sqr(x) ((x)*(x))
#define ms(a,b) memset(a,b,sizeof(a))
#define sz size()
#define be begin()
#define pu push_up
#define pd push_down
#define cl clear()
#define lowbit(x) -x&x
#define all 1,n,1
#define rep(i,n,x) for(int i=(x); i<(n); i++)
#define in freopen("in.in","r",stdin)
#define out freopen("out.out","w",stdout)
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> P;
const int INF = 0x3f3f3f3f;
const LL LNF = 1e18;
const int maxn = 1e5 + 20;
const int maxm = 1e6 + 10;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int dx[] = {-1,1,0,0,1,1,-1,-1};
const int dy[] = {0,0,1,-1,1,-1,1,-1};
const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int n,m,num,ok,u,v;
/*
4—>2
5—>1—>3
正常情况下字典序最小的拓扑序应该是:4 2 5 1 3
这种规则下,则应该是: 5 1 4 2 3
*/
vector<int> G[maxn];
int ans[maxn];
char s[10];
int inDeg[maxn],x;
void topSort()
{
priority_queue<int> q; //优先队列默认的是数据大的优先级高
int num=0;
while(!q.empty()) q.pop();
for(int i=1;i<=n;i++) if(!inDeg[i]) q.push(i);
while(!q.empty())
{
int now = q.top();
q.pop();
ans[++num]=now;
for(int i=0; i<G[now].size(); i++)
{
int nxt = G[now][i];
if(--inDeg[nxt] == 0) q.push(nxt);
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
ms(inDeg,0);
ms(ans,0);
for(int i=1;i<=n;i++) G[i].clear();
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
G[v].push_back(u);
inDeg[u]++;
}
topSort();
for(int i=n;i>=1;i--)
{
if(i!=1) printf("%d ",ans[i]);
else printf("%d\n",ans[i]);
}
}
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 逃生 【拓扑排序+反向建图+优先队列】的更多相关文章
- hdu 4857 逃生 拓扑排序+逆向建图
逃生 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Problem Descr ...
- HDU 2647 Reward 【拓扑排序反向建图+队列】
题目 Reward Dandelion's uncle is a boss of a factory. As the spring festival is coming , he wants to d ...
- hdu 4857 逃生 拓扑排序+PQ,剥层分析
pid=4857">hdu4857 逃生 题目是求拓扑排序,但不是依照字典序最小输出,而是要使较小的数排在最前面. 一開始的错误思路:给每一个点确定一个优先级(该点所能到达的最小的点) ...
- HDU2647(拓扑排序+反向建图)
题意不说了,说下思路. 给出的关系是a要求的工资要比b的工资多,因为尽可能的让老板少付钱,那么a的工资就是b的工资+1.能够确定关系为a>b,依据拓扑排序建边的原则是把"小于" ...
- hdoj--4857--逃生(拓扑排序+反向建图)
逃生 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submiss ...
- hdu 4857 逆向拓扑排序+反向输出
/*一组测试实例 4 4 2 3 1 2 4 */ #include<stdio.h> #include<string.h> #include<queue> usi ...
- Educational Codeforces Round 25 E. Minimal Labels 拓扑排序+逆向建图
E. Minimal Labels time limit per test 1 second memory limit per test 256 megabytes input standard in ...
- 逃生 HDU 4857(反向建图 + 拓扑排序)
逃生 链接 Problem Description 糟糕的事情发生啦,现在大家都忙着逃命.但是逃命的通道很窄,大家只能排成一行. 现在有n个人,从1标号到n.同时有一些奇怪的约束条件,每个都形如:a必 ...
- HDU4857——逃生(反向建图+拓扑排序)(BestCoder Round #1)
逃生 Description 糟糕的事情发生啦,现在大家都忙着逃命.但是逃命的通道很窄,大家只能排成一行. 现在有n个人,从1标号到n.同时有一些奇怪的约束条件,每个都形如:a必须在b之前.同时,社会 ...
随机推荐
- 【bzoj3626】[LNOI2014]LCA 树链剖分+线段树
题目描述 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询 ...
- background 背景图铺满界面
background <body background="/image/1.png" style=" background-repeat:no-repeat ; b ...
- TextView AutoLink, ClikSpan 与长按事件冲突的解决
前言 首先,我们先来复习一下 autoLink 和 ClickableSpan 是干什么用的. autoLink 当中有五个属性值:分别是 phone.email.map.web.all 和 none ...
- redux-saga基本用法
redux-saga是管理redux异步操作的中间件,redux-saga通过创建sagas将所有异步操作逻辑收集在一个地方集中处理. sagas采用Generator函数来yield Effects ...
- Elasticsearch报错
[2018-07-12T10:32:47,642][INFO ][o.e.b.BootstrapChecks ] [VfCcJIq] bound or publishing to a non-loop ...
- angular js 模拟获取后台的数据
在这里我们把后台的数据用一个.json文件进行代替. 项目的目录结构如下: puDongLibraryLearning----ui-router-learning ---- data-------pe ...
- Step-By-Step: Setting up Active Directory in Windows Server 2016
There are interesting new features now made available in Windows Server 2016 such as time based grou ...
- Bash 实例,第二部分
我们先看一下处理命令行自变量的简单技巧,然后再看看 bash 基本编程结构. 接收自变量 在 介绍性文章 中的样本程序中,我们使用环境变量 "$1" 来引用第一个命令行自变量.类似 ...
- 入门级:GitHub和Git超超超详细使用教程!
GitHub和Git入门 考虑到大家以前可能对版本控制工具和Linux命令行工具都不了解,我写了一个简单的博客来让大家学会入门使用方法. GitHub的简单使用 第一步 创建GitHub账号 1. 打 ...
- apply()和call()
每个函数都包含俩个非继承而来的方法:apply() 和 call(),这俩个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值,以扩充函数赖以运行的作用域.一般来讲,thi ...