對有向無環圖(DAG),存在一個節點排列,使得每條邊 u → v 皆滿足 u 在 v 之前。
若圖中有有向環,則拓撲序不存在。
原題:
https://cses.fi/problemset/task/1679
題意
給 n 門課(1…n)與 m 條先修關係 a → b(修 a 才能修 b)。
請輸出一個可行的修課順序;若不存在(有向環)則輸出 IMPOSSIBLE。
解題思路
#include <bits/stdc++.h>
using namespace std;
int main(){
int n, m;
cin >> n >> m;
vector<vector<int>> g(n+1);
vector<int> indeg(n+1, 0);
while(m--){
int a, b; cin >> a >> b; // a -> b
g[a].push_back(b);
indeg[b]++;
}
queue<int> q;
for(int i=1;i<=n;i++) if(indeg[i]==0) q.push(i);
vector<int> order;
while(!q.empty()){
int u = q.front(); q.pop();
order.push_back(u);
for(int v: g[u]){
if(--indeg[v]==0) q.push(v);
}
}
if((int)order.size()!=n){
cout << "IMPOSSIBLE\n";
}else{
for(int i=0;i<n;i++)
cout << order[i] << (i+1==n?'\n':' ');
}
return 0;
}
原題:
https://cses.fi/problemset/task/1681
題意:
給定一張有向無環圖(DAG),求從節點 1 到節點 n 的不同路徑數
解題思路:
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1'000'000'007;
int main(){
int n, m;
cin >> n >> m;
vector<vector<int>> g(n+1);
vector<int> indeg(n+1, 0);
while(m--){
int a,b; cin >> a >> b;
g[a].push_back(b);
indeg[b]++;
}
queue<int> q;
for(int i=1;i<=n;i++) if(indeg[i]==0) q.push(i);
vector<long long> dp(n+1, 0);
dp[1] = 1;
while(!q.empty()){
int u = q.front(); q.pop();
for(int v: g[u]){
dp[v] += dp[u];
if(dp[v] >= MOD) dp[v] -= MOD;
if(--indeg[v]==0) q.push(v);
}
}
cout << dp[n] % MOD << "\n";
return 0;
}
原題:
https://leetcode.com/problems/course-schedule/description/
題意:
numCourses 門課(0…n-1)與先修關係 prerequisites[i] = [a, b](修 b 才能修 a)。
問是否能修完全部課(是否存在拓撲序)。
解題思路:
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<vector<int>> g(numCourses);
vector<int> indeg(numCourses, 0);
for(auto &e: prerequisites){
int a=e[0], b=e[1]; // b -> a
g[b].push_back(a);
indeg[a]++;
}
queue<int> q;
for(int i=0;i<numCourses;i++) if(indeg[i]==0) q.push(i);
int taken = 0;
while(!q.empty()){
int u = q.front(); q.pop();
taken++;
for(int v: g[u]){
if(--indeg[v]==0) q.push(v);
}
}
return taken == numCourses;
}
};
原題:
https://leetcode.com/problems/course-schedule-ii/
題意:
同上題,但需要輸出一個可行的修課順序。若不存在(有環)回傳空陣列。
解題思路:
class Solution {
public:
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
vector<vector<int>> g(numCourses);
vector<int> indeg(numCourses, 0);
for(auto &e: prerequisites){
int a=e[0], b=e[1]; // b -> a
g[b].push_back(a);
indeg[a]++;
}
queue<int> q;
for(int i=0;i<numCourses;i++) if(indeg[i]==0) q.push(i);
vector<int> order;
while(!q.empty()){
int u = q.front(); q.pop();
order.push_back(u);
for(int v: g[u]){
if(--indeg[v]==0) q.push(v);
}
}
if((int)order.size()!=numCourses) return {};
return order;
}
};