(原創)有向圖的傳遞閉包問題

 

Description
KJZ的師弟師妹們最近在學習離散數學,因而他決定出一道簡單的圖論知識考考你們! 在這裏他向你們介紹了一個叫作傳遞閉包的概念。 傳遞閉包就是,在集合X上的二元關係R的傳遞閉包是包含R的X上的最小的傳遞關係。 那麼什麼事有向圖的傳遞閉包呢? 對於有向圖G(V,E)的傳遞閉包便是G(V,E),其中E{(i,j):圖G中包含一條由i到j的路徑}。 讀到這裏的你,若是是一頭霧水的話,證實你集合論學的不是很好,必定要認真聽離散數學的課程喔! 可是KJZ是一名盡職的師兄,他在這裏經過一道題目,向你通俗易懂的介紹什麼是有向圖的傳遞閉包。
Input
每一個輸入只有一組 每組輸入第一行包括一個整數N(1<=N<=300) 接下來N行N列,表明一個矩陣G 若是G[i][j] = 1,表明i有一條邊連向j 若是G[i][j] = 0,表明i沒有邊連向j 且對於1~N,G[i][i]一定等於1 接下來一個數字Q,表明有Q次查詢 (1<=Q<=100000) 接下來有Q行,每行兩個數字u,v
Output
對於每一個查詢u,v,輸出一行,若是u能走到v,輸出1,不然輸出0
Sample Input 1
3
1 1 0
0 1 1
0 0 1
5
1 1
1 3
2 3
3 2
3 1
Sample Output 1
1
1
1
0
0
解題思路:這道題的思路很是巧妙,就是利用Floyd的最短路徑,假設能找到「最短路徑」則證實是連通的,不能則證實不聯通;
Floyd算法大概思想:依次掃描每一點(k),並以該點做爲中介點,計算出經過k點的其餘任意兩點(i,j)的最短距離,這就是floyd算法的精髓
也就是提及點i 直接到達終點 j 最短 仍是從i 出發 通過中間 若干點 k  到達 j 最短;
實現只須要三個循環:
  
1 for(int k = 1 ; k  <= N ;k++)      //k表示的是中間通過的點,這個循環必定要放在最外面
2    for(int i  = 1 ; i <= N; i++) 3        for(int j = 1  ; j <= N ;j++) 4           dp[i][j] = min(dp[i][j],d[i][k]+d[k][j]);      //不斷取「最小」;

迴歸這道題,咱們也能夠以這種思想,從該起點 i 出發,看是否通過中間 k 點 ,能到達 j點;或者從i 直接到達 j 點;ios

代碼以下:算法

 1 #include<iostream>
 2 using namespace std;  3 
 4 
 5 int N;  6 int Q;  7 int x ,y;  8 int G[305][305];  9 int map[305][305]; 10 int main() 11 { 12     cin>>N; 13     for(int i = 1 ;i <= N;i++) 14  { 15         for(int j = 1 ; j <= N;j++) 16  { 17             cin>>G[i][j];           //輸入這個矩陣
18  } 19  } 20       
21     for(int k = 1 ; k <= N ;k++)     //這個中間點的循環必定要放在最外面;
22  { 23         for(int i = 1 ;i <= N; i++) 24  { 25             for(int j = 1 ; j <= N;j++) 26  { 27                 if(G[i][j]==1||G[i][k]==1&&G[k][j]==1) 28                            //直接連通或者間接通過其餘點連通;
29  { 30                     map[i][j] = 1;  //將這兩點連通;
31  } 32  } 33  } 34  } 35     cin>>Q; 36     for(int i = 1 ; i <= Q ;i++) 37  { 38         cin>>x>>y; 39         if(map[x][y]==1)    //判斷兩點是否連通
40         cout<<1<<endl; 41         else cout<<0<<endl; 42  } 43     return 0; 44 }
相關文章
相關標籤/搜索