zoukankan      html  css  js  c++  java
  • Warshall传递闭包算法的学习与实现

    1、问题引入

      一个有n个顶点的有向图的传递闭包为:有向图中的初始路径可达情况可以参见其邻接矩阵A,邻接矩阵中A[i,j]表示i到j是否直接可达,若直接可达,则A[i,j]记为1,否则记为0;两个有向图中i到j有路径表示从i点开始经过其他点(或者不经过其他点)能够到达j点,如果i到j有路径,则将T[i,j]设置为1,否则设置为0;有向图的传递闭包表示从邻接矩阵A出发,求的所有节点间的路径可达情况,该矩阵就为所要求的传递闭包矩阵。。。

    例如:

    有向图为:

    由该有向图可以得到初始的邻接矩阵为:

    那么warshall传递闭包算法的目的就是由邻接矩阵出发,进行探索求出最终的传递闭包:

    2、动态规划求解思路

      动态规划将问题分段,本例warshall算法是通过一系列n阶矩阵r(k)来构造最终阶段n阶传递闭包矩阵r(n)

          R(k) 由它的前趋 R(k-1) 计算得到(分级推进计算)。
          R(0) ——该矩阵不允许它的路径中包含任何中间顶点,即从该矩阵的任意顶点出发的路径不含有中间顶点,此即邻接矩阵。
          R(1) ——允许路径中包含第1个顶点(本例编号 1)作为中间顶点。
          R(2) ——允许路径中包含前2个顶点(本例编号1 2)作为中间顶点。
          R(k) ——允许路径中包含前k个顶点作为中间顶点。
          R(n) ——允许路径中包含全部 n 个顶点作为中间顶点。
          每个后继矩阵 R(k) 对其前趋 R(k-1) 来说,在路径上允许增加一个顶点, 因此有可能包含更多的1(增加前为1的在增加后依然为1)。
    3、具体的算法描述
    1 warshall(A[1...n,1...n]
    2 r(0)<-A;
    3 for(k=1;k<=n;k++)
    4     for(i=1;i<=n;i++)
    5         for(j=1;j<=n;j++)
    6             r(k)[i,j]=r(k-1)[i,j] or(r(k-1)[i,k] and r(k-1)[k,j]);
    7 return r(n);

    4、具体实现代码如下
      说明:(1)有向图的顶点个数和初始邻接矩阵存储在2.txt中(具体如下图),其中4表示有向图中有4 个顶点,其他表示初始邻接矩阵。

         (2)有向图的顶点个数和初始邻接矩阵个数可以随意更改,,,,

         具体代码:

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 void Warshall(int,int**);
     4 void main()
     5 {
     6     int i,j,num;
     7     FILE*p;
     8     p=fopen("2.txt","r");
     9     if(p==NULL)
    10     {
    11         printf("cannot open 2.txt");
    12         exit(-1);
    13     }
    14     fscanf(p,"%d",&num);
    15     int **r=(int**)malloc(sizeof(int*)*(num+1));
    16     for(i=0;i<num+1;i++)
    17         r[i]=(int*)malloc(sizeof(int)*(num+1));
    18     for(i=1;i<num+1;i++)
    19         for(j=1;j<num+1;j++)
    20             fscanf(p,"%d",&r[i][j]);
    21     printf("顶点个数为:%d\n",num);
    22     printf("邻接矩阵为:\n");
    23     for(i=1;i<num+1;i++)
    24     {
    25         for(j=1;j<num+1;j++)
    26             printf(" %d  ",r[i][j]);
    27         printf("\n");
    28     }
    29     Warshall(num,r);
    30     printf("最终的传递闭包为\n");
    31     for(i=1;i<num+1;i++)
    32     {
    33         for(j=1;j<num+1;j++)
    34             printf(" %d  ",r[i][j]);
    35         printf("\n");
    36     }
    37 
    38 }
    39 //三重循环实现的warshall算法
    40 //r为邻接矩阵,中间存储初试的可达与非可达路径情况,1表示可达,0表示不可达
    41 void Warshall(int num,int**r)
    42 {
    43     int i,j,k;
    44     int **temp=(int**)malloc(sizeof(int*)*(num+1));
    45     for(i=0;i<num+1;i++)
    46         temp[i]=(int*)malloc(sizeof(int)*(num+1));
    47     for(k=1;k<=num;k++)//依次取得的可以作为中间点的顶点
    48     {
    49         for(i=1;i<=num;i++)
    50         {
    51             for(j=1;j<=num;j++)
    52             {
    53                 temp[i][j]=(r[i][j])||(r[i][k]&r[k][j]);
    54             }
    55         }
    56         for(i=1;i<=num;i++)
    57             for(j=1;j<=num;j++)
    58                 r[i][j]=temp[i][j];
    59     }
    60 
    61 }

    5、结果如下:

    6、参考文献

    (1)算法导论

    (2)数据结构 严蔚敏

    (3)网上下载的ppt(第8章 动态规划)

     
  • 相关阅读:
    Android 中向本地保存图片的时候,不在图库显示
    shopfiy 二次开发之自定义 sections
    shopfiy 二次开发之条件判断
    Linux中为RabbitMQ调整文件句柄数和socket连接数
    python helium 安装使用
    python log 打印
    linux 查看服务器登录失败的ip和次数
    在阿里云WINDOWS机器上部署的JAVA SpringBoot 时不时的无效 。
    打开TLS 1.1和1.2而不影响其他协议
    美团供应链架构演进
  • 原文地址:https://www.cnblogs.com/lpshou/p/2473109.html
Copyright © 2011-2022 走看看