《算法设计与分析》第四周作业
标签(空格分隔): 课堂作业
姓名:李**
学号:16340114
题目:Course Schedule II(https://leetcode.com/problems/course-schedule-ii/description/)
题目概要
看到题目就知道这是上一周做的Course Schedule的升级版,这次的题目翻译一下就是要将一个有向图进行拓扑排序
思路
和上周一样,应用教科书(Algorithms(Dasgupta))里的思想,把输入的有向图转换成DFS树,得到每个节点的post值,应用如下性质:
Property In a dag, every edge leads to a vertex with a lower post number.
即可得:只需将节点按post值降序排列就可以得到一个拓扑序列。
具体实现
题目的输入是前置课程在后,后置课程在前,建图的时候要将这两个值翻转过来。上一周做的时候并没有留意到这个问题,做错了,毕竟只是找环,图反过来也是环哈哈
建完图进行dfs打上post值,检测回边,有回边即返回空vector表示无法进行拓扑排序。之后将map< vertice, postClock >转换为map< postClock, vertice>(postClock可以作为key),利用map结构与性质,用迭代器遍历map< postClock, vertice >即可得到postClock升序的序列。将得到的序列放入结果vector中,在进行反转得到post值降序的序列,即得到答案。
在做题的时候没留意到vertice的值的取值范围,用了通用的map记录pre,post值,运行起来贼慢(只打败了2.33%的人)。而且似乎没出现在prerequests中的节点就不会被打上标记,还要在最后作一个处理。总之,改进空间还是挺大的。
心得
没想到这个pre和post值能有这么大的用处。
这次做题要看清楚题目的值的范围,说不定就能提高程序效率。
源码:
class Solution
{
public:
Solution()
{
clock = 1;
}
vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites)
{
if (prerequisites.size() == 0)
{
vector<int> specialAnswer;
for (int i = 0; i < numCourses; ++i)
{
specialAnswer.push_back(i);
}
return specialAnswer;
}
//handle input
for (int i = 0; i < prerequisites.size(); ++i)
{
int u = prerequisites[i].second;
int v = prerequisites[i].first;
vertex.insert(u);
vertex.insert(v);
if (edges.find(u) != edges.end())
{
edges[u].insert(v);
}
else
{
set<int> nextVertice;
nextVertice.insert(v);
edges[u] = nextVertice;
}
}
//pre handle
for (auto currentVertice : vertex)
{
visited[currentVertice] = false;
}
//dfs
for (auto currentVertice : vertex)
{
visit(currentVertice);
}
vector<int> answer;
answer.clear();
//check backedge
for (int i = 0; i < prerequisites.size(); ++i)
{
int u = prerequisites[i].second;
int v = prerequisites[i].first;
cout << "u " << preClock[u] << " : " << postClock[u] << endl;
cout << "v " << preClock[v] << " : " << postClock[v] << endl << endl;
if (preClock[v] < preClock[u] && postClock[v] > postClock[u])
{
//has backedge
return answer;
}
}
//topological sorting
map<int, int> postClockToVertice;
for (auto i : postClock)
{
postClockToVertice[i.second] = i.first;
}
for (auto i : postClockToVertice)
{
answer.push_back(i.second);
}
reverse(answer.begin(), answer.end());
while (answer.size() < prerequisites.size())
{
for (int i = 0; i < numCourses; ++i)
{
if (postClock.find(i) != postClock.end())
answer.push_back(i);
}
}
return answer;
}
void preVisit(int currentVertice)
{
preClock[currentVertice] = clock;
clock++;
}
void postVisit(int currentVertice)
{
postClock[currentVertice] = clock;
clock++;
}
void visit(int currentVertice)
{
if (visited[currentVertice])
return;
visited[currentVertice] = true;
preVisit(currentVertice);
for (auto nextVertice : edges[currentVertice])
{
visit(nextVertice);
}
postVisit(currentVertice);
}
private:
int clock;
map<int, int> preClock;
map<int, int> postClock;
map<int, bool> visited;
map< int, set<int> > edges;
set< int > vertex;
};
本文介绍了一种基于深度优先搜索(DFS)的拓扑排序算法实现,用于解决LeetCode上的CourseScheduleII问题。通过将课程之间的依赖关系构建成有向图,并利用节点的post值进行排序,实现了有效的课程安排。文章分享了具体的实现细节、遇到的问题及解决方案。
1920

被折叠的 条评论
为什么被折叠?



