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 點;
代碼如下:
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 }