21 拓扑排序

理论说明

本次我们主要苏里一下图论中的另一个经典问题--拓扑排序,并以该问题作为图论最后一个专题。

设有一个有向无环图DAG,对其进行拓扑排序即求其中结点的一个拓扑序列,对于所有的有向边(U,A),在该序列中结点U都排序在结点V之前。满足该要求的结点序列,我们称为满足拓扑次序的序列。求这个序列的过程,被称为拓扑排序。

基本算法:

 将入度为0的结点放入队列
  while(队列不空) {
     x=队列头
     for(i in (与x相联的结点)) {
       结点i的入度减少1
       if(结点i的队列为0) 入队列
     }
  }
  return 最后一个结点是否已经放入队列

题目来源和说明

来自王道考研九度OJ

题目描述

ACM-DIY is a large QQ group where many excellent acmers get together. It is so harmonious that just like a big family. Every day,many "holy cows" like HH, hh, AC, ZT, lcc, BF, Qinz and so on chat on-line to exchange their ideas. When someone has questions, many warm-hearted cows like Lost will come to help. Then the one being helped will call Lost "master", and Lost will have a nice "prentice". By and by, there are many pairs of "master and prentice". But then problem occurs: there are too many masters and too many prentices, how can we know whether it is legal or not?

We all know a master can have many prentices and a prentice may have a lot of masters too, it's legal. Nevertheless,some cows are not so honest, they hold illegal relationship. Take HH and 3xian for instant, HH is 3xian's master and, at the same time, 3xian is HH's master,which is quite illegal! To avoid this,please help us to judge whether their relationship is legal or not.

Please note that the "master and prentice" relation is transitive. It means that if A is B's master ans B is C's master, then A is C's master.

输入说明

The input consists of several test cases. For each case, the first line contains two integers, N (members to be tested) and M (relationships to be tested)(2 <= N, M <= 100). Then M lines follow, each contains a pair of (x, y) which means x is y's master and y is x's prentice. The input is terminated by N = 0. TO MAKE IT SIMPLE, we give every one a number (0, 1, 2,..., N-1). We use their numbers instead of their names.

输出说明

For each test case, print in one line the judgement of the messy relationship. If it is legal, output "YES", otherwise "NO".

样例展示

输入:
3 2
0 1
1 2
2 2
0 1
1 0
0 0

输出:
YES
NO

C++代码

这里给出两份代码,第一个是基于数组进行了模拟队列和链表

#include<iostream>
using namespace std;

const int N=1000;
int h[N],e[N],ne[N],idx;
int q[N];
int d[N];
int n,m;

void add(int a,int b) {
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}
bool qsort() {
    int hh=0,tt=-1;
    for(int i=0;i<n;i++) {
        if(d[i]==0) q[++tt]=i;
    }
    while(hh<=tt) {
        int t=q[hh++];
        for(int i=h[t];i!=-1;i=ne[i]) {
            int j=e[i];
            d[j]--;
            if(d[j]==0) q[++tt]=j;
        }
    }
    return tt==n-1;
}
int main() {
    while(scanf("%d%d",&n,&m)!=EOF) {
        if(n==0&&m==0) break;
        for(int i=0;i<n;i++) {
            h[i]=-1;
            d[i]=0;
        }
        for(int i=0;i<m;i++) {
            int a,b;
            cin>>a>>b;
            add(a,b);
            d[b]++;
        }
        if(qsort()) {
            puts("Yes");
        }
        else puts("NO");
    }
    return 0;
}

第二种是王道考研给出的解决方案,如下(这种方法更容易理解)

#include<iostream>
#include<vector>
#include<queue>
using namespace std;

vector<int> edge[501]; // 邻接链表
queue<int> Q;

int main() {
    int inDegree[501];
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF) {
        if(n==0&&m==0) break;
        //初始化,入度为0,邻接链表为空
        for(int i=0;i<n;i++) {
            inDegree[i]=0;
            edge[i].clear();
        }
        //读入边,变化度,变化邻接链表
        while(m--) {
            int a,b;
            scanf("%d%d",&a,&b);
            inDegree[b]++;
            edge[a].push_back(b);
        }
        while(Q.empty()==false) Q.pop(); //弹出队列,清空上一组数据
        //入队入度为0的结点
        for(int i=0;i<n;i++) {
            if(inDegree[i]==0) Q.push(i);
        }
        int cnt=0;
        while(Q.empty()==false) {
            int nowP=Q.front(); //取队头
            Q.pop(); //弹出队头
            cnt++; //被确定的结点个数加1
            for(int i=0;i<edge[nowP].size();i++) {
                inDegree[edge[nowP][i]]--;
                if(inDegree[edge[nowP][i]]==0) {
                    Q.push(edge[nowP][i]);
                }
            }
        }
        if(cnt==n) puts("YES");
        else puts("NO");
    }
}


确定比赛名次

https://www.nowcoder.com/questionTerminal/a3a561d688264a8baa31b3edf2610641

C++代码

//这里因为每次**队列的时候需要按照大小进行排序,因此直接用了王道考研的模板换成了优先级队列,其他基本是不变的。但是这个题目耗费了我好长的时间,找了好长时间的bug,没想到是edge开的太小了,只开了500.改成520就对了。
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
const int N=10000;
vector<int> edge[520];
priority_queue<int, vector<int>, greater<int>> Q; //小顶堆
int inDegree[N];
int n,m;
int main() {
    while(scanf("%d%d",&n,&m)!=EOF) {
        for(int i=1;i<=n;i++) {
            inDegree[i]=0;
            edge[i].clear();
        }
        while(m--) {
            int a,b;
            scanf("%d%d",&a,&b);
            inDegree[b]++;
            edge[a].push_back(b);
        }
        while(Q.empty()==false) Q.pop();
        for(int i=1;i<=n;i++) {
            if(inDegree[i]==0) Q.push(i);
        }
        int cnt=1;
        while(Q.empty()==false) {
            int nowP=Q.top();
            Q.pop();
            if(cnt==n)
                cout<<nowP<<endl;
            else
                cout<<nowP<<" ";
            cnt++;
            for(int i=0;i<edge[nowP].size();i++) {
                inDegree[edge[nowP][i]]--;
                if(inDegree[edge[nowP][i]]==0) Q.push(edge[nowP][i]);
            }
        }
    }
}

产生冠军

C++代码

高校夏令营机试训练 文章被收录于专栏

Leetcode题目太多,不知道如何准备高校夏令营?欢迎关注本专栏,和本小白一起准备夏令营吧! 本专题的规划如下: 截止到4月下旬:以王道考研为依托,提供夏令营机考的准备计划,打好基础 截止到5月中旬:以剑指offer进一步加强 本专题的内容如下: 1. 给出题目的在线测试链接,方面您检查代码的正确性 2. 给出题解

全部评论

相关推荐

刚刷到字节跳动官方发的消息,确实被这波阵仗吓了一跳。在大家还在纠结今年行情是不是又“寒冬”的时候,字节直接甩出了史上规模最大的转正实习计划——ByteIntern。咱们直接看几个最硬的数,别被花里胡哨的宣传词绕晕了。首先是“量大”。全球招7000多人是什么概念?这几乎是把很多中型互联网公司的总人数都给招进来了。最关键的是,这次的资源分配非常精准:研发岗给了4800多个Offer,占比直接超过六成。说白了,字节今年还是要死磕技术,尤其是产品和AI领域,这对于咱们写代码的同学来说,绝对是今年最厚的一块肥肉。其次是大家最关心的“转正率”。官方直接白纸黑字写了:整体转正率超过50%。这意味着只要你进去了,不划水、正常干,每两个人里就有一个能直接拿校招Offer。对于2027届(2026年9月到2027年8月毕业)的同学来说,这不仅是实习,这简直就是通往大厂的快捷通道。不过,我也得泼盆冷水。坑位多,不代表门槛低。字节的实习面试出了名的爱考算法和工程实操,尤其是今年重点倾斜AI方向,如果你简历里有和AI相关的项目,优势还是有的。而且,转正率50%也意味着剩下那50%的人是陪跑的,进去之后的考核压力肯定不小。一句话总结:&nbsp;27届的兄弟们,别犹豫了。今年字节这是铁了心要抢提前批的人才,现在投递就是占坑。与其等到明年秋招去千军万马挤独木桥,不如现在进去先占个工位,把转正名额攥在手里。
喵_coding:别逗了 50%转正率 仔细想想 就是转正与不转正
字节7000实习来了,你...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务