题意:有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]);
}
}