Description
小明这个学期必须选修n门课程,课程编号记为0到n-1。
在选修某些课程之前需要一些先修课程。先修课程按数组prerequisites给出,其中prerequisites[i] = [a, b],表示如果要学习课程a则必须先学习课程b。
例如,先修课程对[0, 1]表示:要想学习课程0,则需要先完成课程1。
请判断小明能否完成所有课程的学习,如果可以则输出true,否则输出false。
Input
第一行输入t,表示有t个测试样例。
接着输入n,表示有n门课程,接着输入len,表示prerequisites数组的长度,接着输入prerequisites数组。
以此类推,共输入t个测试样例。
Output
每一行输出能否完成所有课程的学习,若可以则输出true,否则输出false。
共输出t行。
Sample
#0
Input
Copy
3 2 1 1 0 2 2 1 0 0 1 3 3 1 0 2 0 2 1
Output
Copy
true false true
拓扑排序原理:
利用离散数学的入度,
如果1-2,那2的入度就加1,这就是入度
然后入度为0的先排序,先输出。
1的入读为0先出
1出了之后2,3是不是少了1指向他们了,然后2,3的入度-1,然后再重复入度为0的先出
然后2或者3先出一个(拓扑排序可能有多种结果就是这种地方形成的,2,3谁先出其实都是对的)
2出了之后,4的入度-1
然后3的入度为0,3出,4的入度-1,然后为0,4就要出了
然后就排好序了,1-2-3-4或者1-3-2-4都是对的
本题思路分析;
本题的用的是拓扑排序然后判断是否有环,因为这道题的意思是先例如完成了1作业才能写2作业,如果输入的是先完成1,才能完成2,和先完成2才能完成1,构成1-2,2-1,
是不是冲突了,因为我完成1之前必须完成2,完成2之前必须完成1。每次只能完成一个的情况下我怎么按照要求完成
箭头是必须满足的先后顺序,我怎么先满足上面那条线的同时给完成下面那条线,所以判断作业能否按照要求完成可以看最后会不会成环,拓扑排序有环会导致,例如你有8个元素,7,8,成环,7,8会无法排序,就是最后会无法处理。
所以你把你排好序的元素跟总的元素对比,如果少了就能知道有没有成环。
拓扑排序入度为0的弹出,弹出1之后,没有入度为0的了,所以就可以判定成环了,所以就无法按时完成作业。
总共4个元素排序,现在只有1在序列里面是不是,所以有环。
代码如下:
#include <iostream>
#include <queue>
#include <functional>
#include <vector>
using namespace std;
int t;
int n, m;
const int maxn = 1e3 + 10;
int in[maxn];///入度的数组,第n个作业对应n的下标,in[n]对应n这个点入度为多少
vector<int>ss[maxn];///ss是个二维动态数组,假设n行m,列,代表n点到m点
int main()
{
cin >> t;
while (t--)
{
cin >> n >> m;///输入有n个作业,m个要求,类似1-2,先完成1才能完成2
for (int i = 0; i < m; i++)
{
int a, b;
cin >> a >> b;
ss[a].push_back(b);///表示a点到b点
in[b]++;///a到b,所以b的入度加1
}
priority_queue<int, vector<int>, greater<int>>q;///队列里面放入度为0的点,如果入度为0就进入队列q
for (int i = 0; i < n; i++)///查找入度为0的点,拓扑排序是入度为0的点先出
{
if (in[i] == 0)
{
q.push(i);
}
}
vector<int>ans;
while (!q.empty())
{
int u = q.top();///u为入度为0的点
ans.push_back(u);///入读为0的点放进数组ans里,ans是排好序的数组
q.pop();///将这个点pop
for (int i = 0; i < ss[u].size(); i++)///搜索这个u点能到达的点,并让他们入读-1,
{
int v = ss[u][i];///v是u能到达的点
in[v]--;///v的入读-1
if (in[v] == 0)///如果入度为0就放进队列里
{
q.push(v);
}
}
}
///如果没有成环就说明ans排好序的数组里会有n个,因为有环的情况下,有的无法排序,会进入不了ans
if (ans.size() == n)
{
cout << "true" << endl;
}
else
{
cout << "false" << endl;
}
for (int i = 0; i < n; i++)///这里为了应对多个测试样例所以要把数组清空
{
ss[i].clear();
in[i] = 0;
}
}
return 0;
}