《演算法設計與分析》第四周作業
《演算法設計與分析》第四周作業
標籤(空格分隔): 課堂作業
文章目錄
姓名:李**
學號: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;
};