学生時代に誰もがそんな状況に遭遇したことがあると思いますが、上級コースでは基礎コースを修了しないと勉強できないものもあります。「図 11. コース関係図」では、コース C を選択する場合は最初にコース B を完了する必要があり、コース B を選択する場合は最初にコース A を完了する必要があります。
この時点で、「トポロジカルソート」の助けが必要になります。「トポロジカルソート」は、有向非巡回グラフ用のアルゴリズムです。これは、「グラフ」内のすべての頂点を順番に線形に並べ替えることです。つまり、頂点 u と頂点 v がある場合、頂点 v に到達したい場合は、頂点 u に到達する必要があります。次に、「トポロジカルソート」では、頂点 u が頂点 v の前になければなりません。
カーンアルゴリズムの手順は次のとおりです。
- 各ポイントの現在の入次数を記録する度数配列を作成し、すべての値を 0 に初期化します。
- すべてのエッジを走査し、次数配列を更新します
- キューを作成する
- キューが空でない場合、ポイントがキューから取り出され、ソートされた配列に記録され、次数の対応する位置が -1 に設定され、そこから直接到達できるすべてのポイントが検索され、これらのポイントの次数が計算されます。全て1ずつ減ります。
- 度数配列を走査し、最初に見つかった点を値 0 でキューに入れます。
- キューが空でない場合は、2 つのステップでループ 45 を実行します。
スケジュールⅡ
これで、受講するコースの合計が numCourses になり、0 ~ numCourses - 1 で示されます。prerequisites[i] = [ai, bi] という配列の前提条件が与えられます。これは、ai コースを受講する前に bi を受講する必要があることを意味します。
たとえば、コース 0 を学習するには、まずコース 1 を完了する必要があります。これは、一致 [0,1] で示されます。
すべてのコースを完了するために設定した学習の順序を返します。正しい注文が複数ある場合がありますが、どれか 1 つを返品するだけで済みます。すべてのコースを完了できない場合は、空の配列を返します。
効率を向上させるために、エッジを隣接行列に変換して保存します。
public class Solution {
public int[] FindOrder(int numCourses, int[][] prerequisites) {
int[] res=new int[numCourses];
if(numCourses==1)
{
res[0]=0;
return res;
}
int[] degree=new int[numCourses];
bool[,] matrix=new bool[numCourses,numCourses];
for(int i=0;i<numCourses;i++)
{
degree[i]=0;
for(int j=0;j<numCourses;j++)
matrix[i,j]=false;
}
for(int i=0;i<prerequisites.Length;i++)
{
degree[prerequisites[i][0]]++;
matrix[prerequisites[i][1],prerequisites[i][0]]=true;
}
Queue<int> q=new Queue<int>();
int a=0;
do
{
if(q.Count!=0)
{
int degree0=q.Dequeue();
res[a++]=degree0;
degree[degree0]=-1;
for(int i=0;i<numCourses;i++)
if(matrix[degree0,i])
degree[i]--;
}
for(int i=0;i<numCourses;i++)
if(degree[i]==0)
{
q.Enqueue(i);
break;
}
}while(q.Count!=0);
if(a==numCourses)
return res;
else
{
int[] empty=new int[0];
return empty;
}
}
}