【四校联考 #1】字典序

题目描述

你需要构造一个11到nn的排列,使得它满足mm个条件,每个条件形如(ai,bi)(ai,bi),表示aiai必须在bibi前面。在此基础上,你需要使它的字典序最小。

输入数据

第一行两个正整数nn,mm。接下来mm行每行两个数ai,biai,bi。

输出数据

输出一行nn个整数表示答案。如果不存在这样的排列,输出1−1。

样例输入

5 4
5 4
5 3
4 2
3 2

样例输出

1 5 3 4 2

数据范围

对于20%的数据,n,mleq10n,mleq10。

对于40%的数据,n,mleq200n,mleq200。

对于60%的数据,n,mleq1000n,mleq1000。

对于100%的数据,n,mleq100000n,mleq100000。

题目分析

我默认大家都已经会priority_queue的用法了,如果你不会的话,我觉得我这里没有讲这个方面的。

这道题是典型的题目啊!求排序方案数,最优解。你记好:看到排列顺序第一个想到的不是单调优化DP,而是拓扑排序。这是一个求状态的问题的神奇算法,取名topsort。

我们把这n个点都看作是一个点集,编号从1到n。所以一个点的情况是:没有约束条件,或者是至少一个约束条件。有点差分系统的风味了。到这里就可以做了,把边建出来(就是把一个点连到另一个点),用一个队列记录一下起始点,greater的队列是最小堆,我们在取出边的时候继续拓展。用网络流的角度来说:从汇点往回跑即可。这样的点一定是在约束条件下的最佳状态。

最后输出-1的时候,当然是这个队列没有办法开到n次了,比如说出现了矛盾,就是环。判断环可以用dj和spfa,当然大法师也可以。

#include<bits/stdc++.h>
using namespace std;
#define RE register int
#define IL inline
#define N 200001
priority_queue<int,vector<int>,greater<int> >q;
int m,n,cnt,top,head[N],in[N],out[N],ans[N];
struct aa{int v,next;}e[N];
IL void addedge(RE u,RE v){
    e[++cnt]=(aa){v,head[u]},head[u]=cnt,in[v]++;
}int main(){
    freopen("dictionary.in","r",stdin),freopen("dictionary.out","w",stdout);
    cin>>n>>m;
    for (RE i=1,u,v;i<=m;++i)
        cin>>u>>v,addedge(u,v);
    for (RE i=1;i<=n;++i)
        if (!in[i]) q.push(i);
    while(q.size()){
        RE u=q.top();
        ans[++top]=u,q.pop();
        for (RE i=head[u];i;i=e[i].next)
            if(!(--in[e[i].v])) q.push(e[i].v);
    }if(top<n) puts("-1");
    else{for (RE i=1;i<=n;++i) cout<<ans[i]<<" ";
    }return 0;
}

代码说明

我两次才AC,原因是建边的时候,head[u]=e[i].next,我写反了,邻接表的实现哦。我希望我有时间说一下,因为各种自动机也要用。可惜我没法讲,因为太简单了。大家可能不喜欢我的码风,那个freopen我不推荐写在define,我可是有血的教训的。

上课的时候看小情侣传纸条。

猜你喜欢

转载自www.cnblogs.com/aserrrre/p/10555355.html