关于拓扑排序的无用记录

848. 有向图的拓扑序列

给定一个 n 个点 m 条边的有向图,点的编号是 1 到 n,图中可能存在重边和自环。

请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出 −1。

若一个由图中所有点构成的序列 A 满足:对于图中的每条边 (x,y),x 在 A 中都出现在 y 之前,则称 A 是该图的一个拓扑序列。

输入格式
第一行包含两个整数 n 和 m。

接下来 m 行,每行包含两个整数 x 和 y,表示存在一条从点 x 到点 y 的有向边 (x,y)。

输出格式
共一行,如果存在拓扑序列,则输出任意一个合法的拓扑序列即可。

否则输出 −1。

数据范围
1≤n,m≤10^5
输入样例:
3 3
1 2
2 3
1 3
输出样例:
1 2 3

如果只要是个拓扑序列就行的话:
是个容器就能存 >< 喜欢啥就用啥 反正进容器的都是入度为0的,正着取倒着取都无所谓

如果要求输出按字典序排列的拓扑排序序列,那选择有序的容器就行了:
一是优先队列 二是set

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,e;
int in[maxn]={0};
vector<int> res;
vector<int> g[maxn];
bool topSort(){
    //queue<int> q;
    priority_queue<int,vector<int>,greater<int>> q;
    for(int i=1;i<=n;i++){
        if(in[i]==0){
            q.push(i);
        }
    }
    while(!q.empty()){
        int top=q.top();
        res.push_back(top);
        q.pop();
        for(int i=0;i<g[top].size();i++){
            int k=g[top][i];
            in[k]--;
            if(in[k]==0) q.push(k);
        }

        if(res.size()==n) return true;
    }

    return false;
}

int main(){
    cin>>n>>e;
    for(int i=0;i<e;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        g[a].push_back(b);
        in[b]++;
    }

    bool flag=topSort();
    if(!flag) cout<<"-1"<<endl;
    else{
        for(int i:res){
            printf("%d ",i);
        }
    }
}

也可以用set
其实对set我一直了解甚少。。。
直到某个题npy带我的时候才知道set是有序的hhhh。所以在这里可以代替优先队列啦。 当然这个速度会慢一点

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,e;
int in[maxn]={0};
vector<int> res;
vector<int> g[maxn];
set<int> s;
bool topSort(){
    //queue<int> q;
    for(int i=1;i<=n;i++){
        if(in[i]==0){
            s.insert(i);
        }
    }
    while(!s.empty()){
        int top=*s.begin();
        res.push_back(top);
        s.erase(s.begin());
        for(int i=0;i<g[top].size();i++){
            int k=g[top][i];
            in[k]--;
            if(in[k]==0) s.insert(k);
        }

        if(res.size()==n) return true;
    }

    return false;
}

int main(){
    cin>>n>>e;
    for(int i=0;i<e;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        g[a].push_back(b);
        in[b]++;
    }

    bool flag=topSort();
    if(!flag) cout<<"-1"<<endl;
    else{
        for(int i:res){
            printf("%d ",i);
        }
    }
}

STL set的妙处

这篇不错

至于set,还有一些性质…

set的insert和delete是不会影响旁边元素的iterator 然后insert可以指定位置insert(可以复杂度O1 如果位置是对的
位置是错的就自动调用普通insert

  • 底层红黑树 节点方式存储,所以插入删除效率高 时间复杂度就按照RB树分析吧
  • iterator这里就相当于指向节点的指针,内存没有变,指向内存的指针怎么会失效呢(当然被删除的那个元素本身已经失效了)。相对于vector来说,每一次删除和插入,指针都有可能失效,调用push_back在尾部插入也是如此。 而vector插入删除后指针可能会变,当发现内存不够时,要把以前的内存释放,申请更大的内存。
  • 看set的增删改查方法,能够发现这个真的很强。。。。

删除操作
既能删除一个,又能删除一段

  • erase(iterator) ,删除定位器iterator指向的值

  • erase(first,second),删除定位器first和second之间的值
    比如erase(s.begin(),s.end())

  • erase(key_value),删除键值key_value的值

查找操作

  • find() 返回定位器 没找到返回end() ,s.end()

插入操作

既能插入一个 又能插入一段

   int a[] = {1,2,3};
   set<int> s;
   s.insert(a,a+3);
   for(set<int>::iterator iter = s.begin() ; iter != s.end() ; ++iter)
   {
       cout<<*iter<<" ";
   }
   //返回值类型是void

set<int>::iterator=s.insert(5);
//如果原本就有了,那就返回原来的位置
//返回值类型pair<set<int>::iterator,bool>

其他操作

  • lower_bound(key_value) ,返回第一个大于等于key_value的定位器

  • upper_bound(key_value),返回最后一个大于等于key_value的定位器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值