LeetCode:207。コーススケジュール
トポロジカルソート(カーンアルゴリズムは実際には幅優先探索のアイデアです)
トポロジカルソートは、実際には欲張りアルゴリズムを使用します。一言で言えば貪欲アルゴリズム:すべてのステップが最適であり、全体的な状況が最適です。
貪欲のポイントは次のとおりです。現在、エントリー度が0のノードをチームに入れます。
前の頂点がない頂点がグラフから削除されるたびに、ここで実際の削除操作を行う必要はありません。次数配列を設定し、各ラウンドで次数0のノードを出力できます。それを削除し、変更します。尖ったノードの次数(-1で十分)、順番に取得されるノードシーケンスは、トポロジカルソートのノードシーケンスです。グラフ内に削除されていないノードがある場合は、「すべてのコースを完了できない」ことを意味します。
ACコード
class Solution {
public boolean canFinish(int numCourses, int[][] p) {
// 拓扑排序 - 广度优先遍历的思路
int[] inDegree = new int[numCourses];
HashSet<Integer>[] adj = new HashSet[numCourses];
for(int i = 0; i < numCourses; i++) adj[i] = new HashSet<>();
int len = p.length;
for(int i = 0; i < len; i++) {
inDegree[p[i][0]]++;
adj[p[i][1]].add(p[i][0]);
}
Queue<Integer> queue = new LinkedList<>();
// 首先加入入度为 0 的结点
for(int i = 0; i < numCourses; i++) {
if(inDegree[i] == 0) queue.add(i);
}
// 记录已经出队的课程数量
int cnt = 0;
while(!queue.isEmpty()) {
int num = queue.poll();
cnt++;
// 遍历当前出队结点的所有后继结点
for(Integer idx : adj[num]) {
inDegree[idx]--;
if(inDegree[idx] == 0) {
// 入度为 0 了
queue.add(idx);
}
}
}
// 移除掉的课程是否与总课程数相等
return cnt == numCourses;
}
}