拓扑序练习

拓扑序

拓扑序分解法

拓扑排序

事件之间的前后关系会形成一个图形结构

将图形转为序列就是拓扑排序

每次找入度为0的点,添加到队列,并将连接这个点的点的入度-1

再次找入读为0的店

//
// Created by cry on 2024/4/5.
//

#include <iostream>
#include <vector>
#include <set>

using namespace std;
#define MAX_N 2000
int in_degree_tuopupaixu[MAX_N+5]={0};
//关系

void acm_1_9_digui_tuopupaixu_test(){
    vector<vector<int>> g(MAX_N+5);
    int ans[MAX_N+5],cnt=0;
    int n,m;
    cin >> n >>m;
    for(int i=0,a,b;i<m;i++) {
        cin >>a >> b;
        in_degree_tuopupaixu[b]+=1; //入度+=1
        g[a].push_back(b); //a节点添加一个b节点
    }
    //使用优先队列,将点添加到优先队列
    set<int> q;
    for(int i=1;i<=n;i++){
        if(in_degree_tuopupaixu[i]==0){
            q.insert(i);//添加入度为0的点
        }

    }
    while(q.size()>0){ //循环直到队列不为空
        int now=*q.begin(); //取到堆顶元素
        q.erase(q.begin()); //出队 堆顶元素
        //答案就在出队的过程,就是now
        ans[cnt++]=now;
        for(int i=0,I=g[now].size();i<I;i++){
            int t=g[now][i]; //指向的节点的编号的入度-1
            in_degree_tuopupaixu[t]-=1;
            if(in_degree_tuopupaixu[t]==0){
                q.insert(t);
            }
        }
    }
    for(int i=0;i<cnt;i++){
        if(i)cout <<" ";
        cout <<ans[i];
    }

}
int main(){
	acm_1_9_digui_tuopupaixu_test();
	return 0;
}

python的优先队列为heapq

pq=[] #初始化
heapq.heappush(pq,4) #添加
heapq.heapppo(pq) #弹出最小元素
#!/usr/bin/python3
# _*_ coding: utf-8 _*_
#
# Copyright (C) 2024 - 2024 Cry, Inc. All Rights Reserved 
#
# @Time    : 2024/4/5 17:51
# @Author  : Cry
# @File    : 拓扑排序.py
# @IDE     : PyCharm
from collections import deque


# 拓扑排序
# 样例输入
# 7 6 //表示7个点,m行
# 1 2
# 1 4
# 2 3
# 4 5
# 3 6
# 5 6
# 样例输出
# 1 2 3 4 5 6 7
import heapq
def tuopu_test():
    n,m=map(int,input().split())
    MAX_N=2000+5
    g=[[] for _ in range(MAX_N)]
    ans=[0]*MAX_N
    inde=[0]*MAX_N
    for i in range(m):
        a,b=map(int,input().split())
        inde[b]+=1;
        g[a].append(b)
    q=[]
    cnt=0
    for i in range(1,n+1):
        if(inde[i]==0):
            heapq.heappush(q,i);
    while(len(q)>0):
        now=heapq.heappop(q)
        ans[cnt]=now
        cnt+=1
        for i in range(len(g[now])):
            t=g[now][i]
            inde[t]-=1
            if(inde[t]==0):
                heapq.heappush(q,t)

    for i in range(cnt):
        if i:
            print(" ",end="")
        print(ans[i],end="")
tuopu_test()

HZOJ 636 旅行计划

//
// Created by cry on 2024/4/5.
//
#include <iostream>
#include <vector>
#include <queue>

using namespace std;
#define MAX_N 100000
void acm_1_9_digui_lvxingjihua_test(){
    int n,m;
    scanf("%d%d",&n,&m);
    int indeg[MAX_N+5]={0};
    vector<vector<int>> g(MAX_N+5);
    for (int i=0,x,y;i<m;i++){
        scanf("%d%d",&x,&y);
        indeg[y]+=1;
        g[x].push_back(y);
    }
    int ans[MAX_N+5]={0};
    queue<int> q;
    for(int i=1;i<=n;i++){
        if(indeg[i]) continue;
        q.push(i);
        ans[i]=1;
    }
    //拓扑求解
    while(!q.empty()){
        int now=q.front();

        q.pop();
        for(int i=0,I=g[now].size();i<I;i++){
            int t=g[now][i];
            indeg[t]-=1;
            if(indeg[t]==0){
                q.push(t);
            }
            ans[t]=max(ans[now]+1,ans[t]); //找最大值
        }

    }
    //输出ans
    for(int i=1;i<=n;i++){
        printf("%d\n",ans[i]);
    }
}
int main(){
	acm_1_9_digui_lvxingjihua_test();
	return 0;
}

python

用deque的popleft和append

#!/usr/bin/python3
# _*_ coding: utf-8 _*_
#
# Copyright (C) 2024 - 2024 Cry, Inc. All Rights Reserved 
#
# @Time    : 2024/4/5 20:17
# @Author  : Cry
# @File    : 旅行计划.py
# @IDE     : PyCharm
from collections import deque


def test():
    MAX_N=100005
    n,m=map(int,input().split())
    indeg=[0]*MAX_N #各个节点入度
    ans=[0]*MAX_N #结果
    q=deque() #队列
    g=[[] for _ in range(MAX_N)]
    for i in range(m):
        a,b=map(int,input().split())
        indeg[b]+=1 #节点入度+1
        g[a].append(b) #a节点连接b节点
    for i in range(1,n+1):
        if(indeg[i]):
            continue
        q.append(i) #如果入度为0,添加到队列
        ans[i]=1;
    while(q):
        now=q.popleft() #取出队列元素
        for i in range(len(g[now])):
            t=g[now][i]
            indeg[t]-=1 #将连接入度为0的点的节点入度-1
            if(indeg[t]==0): #-1后入度为0就添加到队列
                q.append(t)
            ans[t]=max(ans[t],ans[now]+1) #找最大的
    for i in range(1,n+1):
        print(ans[i])
test()

归并排序O(nlogn)

一共logn层,每层归并n次 :nlogn

  1. 分治 :每次分两份,一直分到足够小,比如两个,足够小的进行排序
  2. 归并:先左边后右边,小份进行合并且排序(用指针比较较小的,放入temp完成归并)
//
// Created by cry on 2024/4/5.
//
#include <iostream>
using namespace std;
int *buff_guibing;
#define BIG_DATA_N 10000
void acm_1_6_paixu_guibing(int *arr,int l,int r){ //arr待排序数组 l和r为排序范围
    if (r-l<=1) return ; //小于等于1个,不需要排序
    int mid=(l+r)/2;
    //先左右分治
    acm_1_6_paixu_guibing(arr,l,mid);
    acm_1_6_paixu_guibing(arr,mid,r);
    //归并
    int p1=l,p2=mid,k=0; //p1 p2为两个数组的起始位置,k为temp数组起始位置
//    int *temp=(int *) malloc(sizeof(int)*(r-l)); //temp可以改进,放到外面
    while(p1<mid || p2<r){
        if(p2==r || p1<mid && arr[p1]<=arr[p2]){
            //什么时候将第一个元素放到temp?
            //1.p2为空
            //2.p1不为空 且p1的值小于p2的值
//            temp[k++]=arr[p1++];
            buff_guibing[k++]=arr[p1++];
        }
        else{ //否则就是p2放到temp
//            temp[k++]=arr[p2++];
            buff_guibing[k++]=arr[p2++];
        }
    }
    //将temp元素复制回arr
    for(int i=l;i<r;i++){
//        arr[i]=temp[i-l];
        arr[i]=buff_guibing[i-l];
    }
    //销毁temp
//    free(temp);
    return;
}


void acm_1_6_paixu_guibing_test() {
    // 创建一个随机整数数组
    int n = 10;
    int arr[n];
    for (int i = 0; i < n; i++) {
        arr[i] = rand() % 100;
    }

    // 打印原始数组
    cout << "原始数组: ";
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
    //将temp放到外面,直接一次开辟足够大的空间
    buff_guibing=(int *)malloc(sizeof(int)*BIG_DATA_N);
    // 对数组进行快速排序
    acm_1_6_paixu_guibing(arr, 0, n);
    free(buff_guibing);
    // 打印排序后的数组
    cout << "排序后数组: ";
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;

}

归并排序转非递归

将[0,10)分成[0,5)和[5,10)

[0,5)分成[0,2)和[2,5)

[5,10)分成[5,7)和[7,10)

将以上当成要递归的图,递归为从下到上从[0,2)到[0,5)到[0,10)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

厨 神

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值