最小拓扑序
topsort.pas/c/cpp
【题目描述】
给一个有向无环图,求其字典序最小的拓扑序。
一个拓扑序被认为字典序{pi}最小当且仅当对于任何其他拓扑序{qi},均存在正整数k,使得对于所有i
【输入】
输入第一行包含两个数n, m分别表示有向无环图的点数和边数。
接下来m行,每行两个数ai, bi,表示图中存在一条ai指向bi的有向边。
【输出】
输出n个数,每个数用空格隔开,表示该图的拓扑序。
【输入样例】
3 1
2 1
【输出样例】
2 1 3
【样例解释】
2, 1, 3
2, 3, 1
3, 2, 1
均为合法拓扑序,但是2, 1, 3为最小字典序的拓扑序。
【数据规模】
50%的数据满足:n<=1000
100%的数据满足:1<=n<=100000, 1<=m<=100000, 1<=ai, bi<=n
保证数据至少存在一种合法的拓扑序列
如果直接枚举与入度为0的点相连的点,时间复杂度就太高了(n*n),所以在进行排序的时候,我们用前向星和优先队列来优化,复杂度是(n+m)
【话说师兄的指针好难看懂……_(:зゝ∠)_】
代码如下
#include
#include
#include
#include
using namespace std;
priority_queue<int, vector<int>, greater<int> > q;//优先输出小的数的优先队列
int n,m;
int t=0;
int head[100001];
struct node{
int to,next;
}e[100001];
int father[100001];//记录入度
void add(int u,int v)
{
t++;
e[t].to=v;
e[t].next=head[u];
head[u]=t;
}
void read()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
father[b]++;
add(a,b);
}
for(int i=1;i<=n;i++)
{
if(father[i]==0)
{
q.push(i);
father[i]--;
}
}
}
void work()
{
while(!q.empty())
{
int p=q.top();
q.pop();
printf("%d ",p);
int p1=head[p];
while(p1!=0)
{
father[e[p1].to]--;
if(father[e[p1].to]==0) q.push(e[p1].to);
p1=e[p1].next;
}
}
}
int main()
{
freopen("topsort.in","r",stdin);
freopen("topsort.out","w",stdout);
read();
work();
return 0;
}