1. 程式人生 > >《演算法設計與分析》第四周作業

《演算法設計與分析》第四周作業

《演算法設計與分析》第四周作業

標籤(空格分隔): 課堂作業

文章目錄

姓名:李**
學號: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; };