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 点;
代码如下:
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 }