6-06. 任务调度的合理性(25) -- 拓扑排序

时间:2022-06-15 20:06:13
题目地址: http://www.patest.cn/contests/ds/6-06

假定一个工程项目由一组子任务构成,子任务之间有的可以并行执行,有的必须在完成了其它一些子任务后才能执行。“任务调度”包括一组子任务、以及每个子任务可以执行所依赖的子任务集。

比如完成一个专业的所有课程学习和毕业设计可以看成一个本科生要完成的一项工程,各门课程可以看成是子任务。有些课程可以同时开设,比如英语和C程序设计,它们没有必须先修哪门的约束;有些课程则不可以同时开设,因为它们有先后的依赖关系,比如C程序设计和数据结构两门课,必须先学习前者。

但是需要注意的是,对一组子任务,并不是任意的任务调度都是一个可行的方案。比如方案中存在“子任务A依赖于子任务B,子任务B依赖于子任务C,子任务C又依赖于子任务A”,那么这三个任务哪个都不能先执行,这就是一个不可行的方案。你现在的工作是写程序判定任何一个给定的任务调度是否可行。

输入格式说明:

输入说明:输入第1行给出子任务数N(<=100),子任务按1~N编号。随后N行,每行给出一个子任务的依赖集合:首先给出依赖集合中的子任务数K,随后给出K个子任务编号,整数之间都用空格分隔。

输出格式说明:

如果方案可行,则输出1,否则输出0。

样例输入与输出:

序号 输入 输出
1
4
0
1 1
1 1
2 2 3
1
2
12
0
0
2 1 2
0
1 4
1 5
2 3 6
1 3
2 7 8
1 7
1 10
1 7
1
3
4
1 4
2 1 4
1 2
1 3
0

拓扑排序-学习网址参考:
http://www.tyut.edu.cn/kecheng1/site01/suanfayanshi/topological_sort.asp

/* http://www.patest.cn/contests/ds/6-06 6-06. 任务调度的合理性(25) */
#include <cstdio> 
#include <sstream> 
#include <cstring> 
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <algorithm>
#include <sstream>
#include <cmath>
#include <set>
#include <map>
#include <unordered_map>
#include <stack>
#include <iterator>

using namespace std;

#define N 102
int n;

int in_degree[N];
vector<int> v[N];

bool tuopu()
{
    int i, j;
    int num = 0;
    while (num < n)
    {
        i = 1;
        while (in_degree[i] != 0) // 寻找入度为0的节点
        {
            i++;
        }
        if (i > n){
            return false;
        }

        num++;
        in_degree[i] = -1; // 删掉该节点
        int len = v[i].size(); // 删掉相应的边,也就是入度需要减掉
        for (j = 0; j < len; j++)
        {
            in_degree[v[i][j]] --;
        }
    }
    return true;
}

int main()
{
    //freopen("in", "r", stdin);
    int i, j, k;
    while (scanf("%d", &n) != EOF)
    {
        int tmpK,tmp;
        // 初始化 入度全部为0 , 邻接表清空
        for (i = 1; i <= n; i++)
        {
            in_degree[i] = 0;
            v[i].clear();
        }
        for (i = 1; i <= n; i++)
        {
            scanf("%d", &tmpK);
            for (j = 0; j < tmpK; j++)
            {
                scanf("%d", &tmp);
                in_degree[i] ++; // 相应的入度增加
                v[tmp].push_back(i); // 每一个节点的邻接表
            }
        }
        if (tuopu())
            printf("1\n");
        else
            printf("0\n");
    }
    //printf("\n");
    return 0;
}