题意:有一个有向无环图,然后要给每个结点附上标签,如果从v到u有一条边,那么v的标签小于u的标签,那么v的标签要小于u的标签,最后使得从顶点1到顶点n的字典序最小,输出这个字典序
题解:这题一眼看上去用拓扑排序,然后拍了个正向拓扑排序+每次找出最小的进入队列中进行查找,wa6,仔细分析一波,如果图示这样的
那么按照正向拓扑的方法下来排序是1423,实际上答案是1342,这就得考虑一个问题就是真正的让标号小的标签也小,那么应该怎么做呢?使用反向拓扑排序,使用大根堆进行入队,然后从后往前赋值,就完美的解决了这个问题。
附上代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+50;
int cnt[maxn],used[maxn],ans[maxn];
struct edge{
int u,v,next;
}edges[maxn];
int head[maxn],tot;
void add_edge(int a,int b)
{
edges[tot].u=a;
edges[tot].v=b;
edges[tot].next=head[a];
head[a]=tot++;
}
int main()
{
int n,m;
memset(head,-1,sizeof(head));
tot=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
add_edge(v,u);
cnt[u]++;
}
priority_queue<int>q;
for(int i=1;i<=n;i++){
if(cnt[i]==0){
q.push(i);
}
}
int temp=n;
while(!q.empty()){
int u=q.top();
ans[u]=temp--;
used[u]=true;
q.pop();
for(int i=head[u];i!=-1;i=edges[i].next){
int to=edges[i].v;
if(used[to]==true){
continue;
}
cnt[to]--;
if(cnt[to]==0){
q.push(to);
}
}
}
printf("%d",ans[1]);
for(int i=2;i<=n;i++){
printf(" %d",ans[i]);
}
return 0;
}