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
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
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 }