HDU-4857逃生(反向拓扑排序)(重点是思想)
来源:互联网 发布:java流行框架2017 编辑:程序博客网 时间:2024/05/21 06:13
题意:有N个人,M个优先级a,b表示a优先于b,并且每个人有个编号的优先级,输出顺序。
这道题一看也许你就知道是拓扑排序,但是这个和普通 的拓扑有些不一样!!
先来看看拓扑的讲解(做此题的时候我还不会拓扑)、
拓扑排序的原理及其实现
刚开始我就是用普通的拓扑排序+优先队列
让队列中最小的先出队~
当时我觉得没有什么不对!
附上代码:
#include<stdio.h>#include<queue>#include<string.h>#include<algorithm>#include<iostream>using namespace std;const int maxn=100000+10;const int MAXN=30000+10;int u[maxn],v[maxn];int input[MAXN],list[MAXN];int first[MAXN],NEXT[maxn],vis[MAXN];bool map0[MAXN][MAXN];int main(){ int T; scanf("%d",&T); while(T--) { int n,m; scanf("%d%d",&n,&m); memset(input,0,sizeof(input)); memset(first,-1,sizeof(first)); memset(vis,0,sizeof(vis)); for(int i=1; i<=m; i++) { scanf("%d%d",&u[i],&v[i]); input[v[i]]++; NEXT[i]=first[u[i]]; first[u[i]]=i; }// for(int i=1;i<=n;i++)// {// printf("%d ",input[i]);// }// printf("\n"); priority_queue< int,vector<int>,greater<int> >q; for(int i=1; i<=n; i++) //先把入度为1先扔进去 { if(input[i]==0) { q.push(i); } } int step=0; while(!q.empty()) { int top=q.top(); q.pop(); int k=first[top]; while(k!=-1) { input[v[k]]--; if(input[v[k]]==0) {// printf("%d*-*\n",v[k]); q.push(v[k]); } k=NEXT[k]; } list[++step]=top; } for(int i=1; i<=step; i++) { printf("%d ",list[i]); } printf("\n"); }}
天真的以为我一直先输出的是队列中最小的数,这么排出顺序一定是小的在钱,大的比较靠后
然而有一组数据
1
10 9
6 4
4 1
3 9
9 2
5 7
7 8
1 10
2 10
8 10
上面代码输出是 :3 5 6 4 1 7 8 9 2 10
但是发现1不是最靠前的
题意是如果有多种情况,必须先考虑1先走,然后才考虑2走,然后考虑3
就是如果没说1在2后面(直接或者间接的关系表面1在2后面),那么1就要在2前面
那么这样你就会发现这个输出是错误的!!
正确的应该是 6 4 1 3 9 2 5 7 8 10
这样1在2前面而题意说3在2前面,这组输出就是我们要的答案
然而如何得到这组答案这是思维的重点
首先看看为什么会出现这种错误??
其实根源就是优先队列的毛病
出队的时机不对,如果把握出队的时机?
我们要最小的在前面(最小的先出)然而在队列中最小的是时刻在变!!
比如1还没有进入队列的时候2是最小的,当1进入队列后1才是最小的!!
这样导致一个结果是,如果2先进队列了,那么2的最小的,先出去了!!然后1进来了
那么根本无法保证1和2的出队顺序是一直是1在2前面
然而我们换个思路,这个问题是出队出的早了!!
那么我们让出队出晚点,让大的数先出队!!!
相对的,小的数就会留在队列中!!(越小越留到最后)
这样1和2肯定能同时留在队列中,而1肯定要比2后出
这样保证了1和2的绝对出栈顺序,然后反过来输出就OK了!!
#include<stdio.h>#include<queue>#include<string.h>#include<algorithm>#include<iostream>using namespace std;const int maxn=100000+10;const int MAXN=30000+10;int u[maxn],v[maxn];int input[MAXN],list[MAXN];int first[MAXN],NEXT[maxn],vis[MAXN];bool map0[MAXN][MAXN];int main(){ int T; scanf("%d",&T); while(T--) { int n,m; scanf("%d%d",&n,&m); memset(input,0,sizeof(input)); memset(first,-1,sizeof(first)); memset(vis,0,sizeof(vis)); for(int i=1; i<=m; i++) { scanf("%d%d",&u[i],&v[i]); input[u[i]]++; NEXT[i]=first[v[i]]; first[v[i]]=i; }// for(int i=1;i<=n;i++)// {// printf("%d ",input[i]);// }// printf("\n"); priority_queue<int>q; for(int i=1; i<=n; i++) //先把出度为0先扔进去 { if(input[i]==0) { q.push(i); } } int step=0; while(!q.empty()) { int top=q.top(); q.pop(); int k=first[top]; while(k!=-1) { input[u[k]]--; if(input[u[k]]==0) {// printf("%d*-*\n",v[k]); q.push(u[k]); } k=NEXT[k]; } list[++step]=top; } for(int i=step; i>=2; i--) { printf("%d ",list[i]); } printf("%d\n",list[1]); }}
- HDU-4857逃生(反向拓扑排序)(重点是思想)
- HDU-4857-逃生【拓扑排序】(反向排序)
- HDU 4857-逃生(反向拓扑排序-按条件排序)
- HDU - 4857 逃生(反向建图 + 拓扑排序)
- HDU 4857 逃生 (反向拓扑排序+优先队列)
- HDU 4857 逃生 (拓扑排序+反向建图)
- HDU 4857--逃生【拓扑排序 && 反向拓扑】
- hdu 4857 逃生(反向拓扑)
- hdu 4857 逃生【反向拓扑排序】
- 反向拓扑排序 HDU 4857 逃生
- hdu 4857 逃生 反向拓扑排序
- HDU-#4857 逃生(拓扑排序)
- hdu 4857 逃生(拓扑排序)
- hdu 4857 逃生(拓扑排序)
- HDU 4857 逃生(拓扑排序)
- HDU 4857 逃生 (拓扑排序)
- hdu 4857 逃生(拓扑排序)
- hdu 4857 逃生(拓扑排序)
- 【SQL】连接(五):交叉连接
- HttpUrlConnection进行跨应用请求
- docker在windows下的安装和配置
- Leftmost Digit
- opengl es 纹理
- HDU-4857逃生(反向拓扑排序)(重点是思想)
- log4j2.x架构分析与实战
- http性能测试
- hdu4857 逃生
- 封装rhel6.5的虚拟机
- Struts2(十二):国际化
- Reclyclerview 的条目的textview展开,收起
- PAT 1029旧键盘
- leetcode -- 557. Reverse Words in a String III 【字符反转 + 字符数组 + 双指针 + 状态记录】