[力扣c语言实现]207. 课程表(拓扑排序)

207. 课程表(拓扑排序)

1. 题目描述

你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。

在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi 。

例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。
请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。

示例 1:

输入:numCourses = 2, prerequisites = [[1,0]]
输出:true
解释:总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。这是可能的。
示例 2:

输入:numCourses = 2, prerequisites = [[1,0],[0,1]]
输出:false
解释:总共有 2 门课程。学习课程 1 之前,你需要先完成​课程 0 ;并且学习课程 0 之前,你还应先完成课程 1 。这是不可能的。

提示:

1 <= numCourses <= 105
0 <= prerequisites.length <= 5000
prerequisites[i].length == 2
0 <= ai, bi < numCourses
prerequisites[i] 中的所有课程对 互不相同

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/course-schedule
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2.代码如下

typedef struct st_Queue
{
	int array[2000];
	int head;
	int tail;
	int size;
}Queue;

#if 0
使用队列,动态地维护了结点的出入队动作代表的遍历与否。
#endif

void enqueue(Queue *queue,int val)
{
	queue->array[queue->tail] = val;
	queue->tail += 1;
	queue->size += 1;
}

int dequeue(Queue *queue)
{
	int tmp = queue->array[queue->head];
	queue->head += 1;
	queue->size -= 1;
	return tmp;
}

void que_init(Queue *queue)
{
	memset(queue,0,sizeof(Queue));
}



bool canFinish(int numCourses, int** prerequisites, int prerequisitesSize, int* prerequisitesColSize){

	int i = 0,j = 0;
	int *degree = NULL;
	int **map = NULL;	
	int *res = NULL;
	int tmpval = 0;
	int cnt = 0;
	Queue g_queue;

	que_init(&g_queue);

	degree = (int *)malloc(sizeof(int)*numCourses);
	memset(degree,0,sizeof(int)*numCourses);
	
	map = (int **)malloc(sizeof(int *)*numCourses);
	memset(map,0,sizeof(int *)*numCourses);

	for (i = 0;i < numCourses;i++)
	{
		map[i] = (int *)malloc(sizeof(int)*numCourses);
		memset(map[i],0,sizeof(int)*numCourses);
	}
	
	for (j = 0; j < prerequisitesSize;j++)//使用degree记录每个课程的出入度
	{
		degree[prerequisites[j][0]] += 1;//入度
		map[prerequisites[j][1]][prerequisites[j][0]] = 1;
	}
	
    for (j=0;j<numCourses;j++)
    {
        if (degree[j] == 0)
        {
			enqueue(&g_queue,j);
        }
    }
	
	while (g_queue.size != 0)
	{
		tmpval = dequeue(&g_queue);
		cnt++;
		for (i = 0 ;i < numCourses;i++)
		{
			if (map[tmpval][i] == 1)//找到节点
			{
				degree[i] -= 1;//入度-1
				if (degree[i] == 0)//如果入度为0,则入队
				{
					enqueue(&g_queue,i);
				}
			}
		}
	}
	
	for (i = 0;i < numCourses;i++)
	{
		free(map[i]);
	}
	
	free(map);
	free(degree);
    
	if (cnt != numCourses)
	{
		return false;
	}

	return true;
}

c++实现

/*
 *  date:   2024-06-06
 *  city:   hangzhou
 *  author: zhangyb
 */
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <memory>

using namespace std;

struct Node {
    Node(int val)
        : val_(val)
    {
    }
    int val_;
    std::set<shared_ptr<Node>> in;
    std::set<shared_ptr<Node>> out;
};

class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        std::map<int, std::shared_ptr<Node>> valToNode;

        auto getNode = [&valToNode](int val) -> std::shared_ptr<Node>{
            auto nodeIter = valToNode.find(val);
            if (nodeIter != valToNode.end())
                return nodeIter->second;
            auto newNodePtr = std::shared_ptr<Node>(new Node(val));
            valToNode.insert({val, newNodePtr});
            return newNodePtr;
        };

        for (auto& prerequisite : prerequisites) {
            auto selfNode = getNode(prerequisite[0]);
            auto preNode = getNode(prerequisite[1]);
            if (selfNode == preNode)
                return false;
            selfNode->out.insert(preNode);
            preNode->in.insert(selfNode);
        }

        std::queue<std::shared_ptr<Node>> nodesWithZeroIn;

        for (auto& [_, nodePtr] : valToNode) {
            if (nodePtr->in.size() == 0)
                nodesWithZeroIn.push(nodePtr);
        }

        while ((int)nodesWithZeroIn.size() > 0) {
            auto nodePtr = nodesWithZeroIn.front();
            nodesWithZeroIn.pop();
            for (auto& outNodePtr : nodePtr->out) {
                outNodePtr->in.erase(nodePtr);
                if ((int)outNodePtr->in.size() == 0) {
                    nodesWithZeroIn.push(outNodePtr);
                }
            }
        }

        for (auto& [_, nodePtr] : valToNode) {
            if (nodePtr->in.size() != 0)
                return false;
        }
        return true;
    }
};

为每个课程构建节点,设置出入度,最终从入度为0的节点入手,将他们一一从图中移除,移除,即,将它们指向的节点的入度节点集合in中删除该节点,并判断移除以后这些节点的入度是否为0,为0就将它们加入入度为0的节点队列中.
最终判断是否还有节点的入度不为0,不为0说明存在环,即循环依赖,则不满足.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值