算法练习(27):Course Schedule

题意:给出有向图,判断是否有环

分析与思路:题目看上去简单,但是没有一个套路还是挺难想的,求有向图是否有环,有一个思路清晰又实用的方法,就是用dfs遍历同时判断是否有回边,pre[node]和post[node]分别代表访问这个点的开始时间和离开时间,一个边u->v若满足pre(v)<pre(u)<post(u)<post(v)则为回边(这是一个定理,怎么证明具体可以百度),有一个小问题就是给出的图不一定是连通的,可以找出所有入度为0的节点保存起来作为源集合,对于每个源都来dfs一遍就可以。具体有个问题就是当你访问节点u时是还不知道post(u)或者可能还不知道post(v)的值的。这个可以隐形比较,当深搜到点u时,对于u指向的所有节点v,若pre[v]有值则必有pre[v]<pre[u],同样道理,若post[v]没有设置过,则最后必有post[u]<post[v],所以判断条件可以转化为判断是否存在指向的节点满足pre[v]已设置过值同时post[v]没设置过值的,则u->v为回边

代码:

class Solution {
public:
	vector<bool> isVisited;//可以用pre代替的
	vector<int> pre;
	vector<int> post;
	int clock;
	bool dfs(int nowNode, vector<pair<int, int>>& prerequisites) {
		isVisited[nowNode] = true;
		pre[nowNode] = clock++;
		for (int i = 0; i < prerequisites.size(); i++) {
			if (prerequisites[i].first == nowNode) {
				if (isVisited[prerequisites[i].second] == true && post[prerequisites[i].second] == -1) return false;//有回边
				else if (isVisited[prerequisites[i].second] == false) {
					if (!dfs(prerequisites[i].second, prerequisites)) return false;
				}
			}
		}
		post[nowNode] = clock++;
		return true;
	}
	bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
		if (prerequisites.size() == 1) return true;
		isVisited=vector<bool>(numCourses, false);//标记是否访问过
		pre=vector<int>(numCourses, -1);
		post = vector<int>(numCourses, -1);
		clock = 0;
		vector<int> toVisited;//源集合
		bool flag = true;
		vector<bool> hasIn(numCourses, false);//判断找出源
		for (int i = 0; i < prerequisites.size(); i++) {
			hasIn[prerequisites[i].second] = true;
		}
		for (int i = 0; i < hasIn.size(); i++) {
			if (hasIn[i] == false) toVisited.push_back(i);
		}
		if (toVisited.empty()) flag = false;//没有源
		if (flag != false) {
			for (int i = 0; i < toVisited.size(); i++) {
				if (!dfs(toVisited[i], prerequisites)) {
					flag = false;
					break;
				}
			}
		}
		for (int i = 0; i < numCourses; i++) {//是否有把所有点遍历过
			if (!isVisited[i]) return false;
		}
		return flag;
	}
};


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值