《算法设计与分析》第四周作业

本文介绍了一种基于深度优先搜索(DFS)的拓扑排序算法实现,用于解决LeetCode上的CourseScheduleII问题。通过将课程之间的依赖关系构建成有向图,并利用节点的post值进行排序,实现了有效的课程安排。文章分享了具体的实现细节、遇到的问题及解决方案。

《算法设计与分析》第四周作业

标签(空格分隔): 课堂作业

姓名:李**
学号: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;
        
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值