• (原创)有向图的传递闭包问题


    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 }
     
  • 相关阅读:
    相信未来 ————11月份做题记录
    noi 滚cu后7月oi生活
    博客已经迁移到 http://imbotao.top 也会同步到这儿
    构建第一个SpringBoot工程
    Spring 事务管理
    IntelliJ IDEA 使用技巧
    JS 获取字符串实际长度
    读《程序员修炼之道》
    读《如何高效学习》
    SQL 语句优化方法
  • 原文地址:https://www.cnblogs.com/yewanting/p/10592004.html
Copyright © 2020-2023  润新知