Minimal Labels CodeForces - 825E (反向拓扑排序+优先队列)

传送门

题意:有一个有向无环图,然后要给每个结点附上标签,如果从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;
}

猜你喜欢

转载自blog.csdn.net/zhouzi2018/article/details/84934843