Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4536781
  • 博文数量: 1214
  • 博客积分: 13195
  • 博客等级: 上将
  • 技术积分: 9105
  • 用 户 组: 普通用户
  • 注册时间: 2007-01-19 14:41
个人简介

C++,python,热爱算法和机器学习

文章分类

全部博文(1214)

文章存档

2021年(13)

2020年(49)

2019年(14)

2018年(27)

2017年(69)

2016年(100)

2015年(106)

2014年(240)

2013年(5)

2012年(193)

2011年(155)

2010年(93)

2009年(62)

2008年(51)

2007年(37)

分类: C/C++

2014-03-24 23:20:47

文章来源:http://www.cnblogs.com/lpshou/archive/2012/04/27/2473109.html

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、具体的算法描述
warshall (A[1...n,1...n])
r(0)<-A;
for(k=1;k<=n;k++)
   for(i=1;i<=n;i++)
       for(j=1;j<=n;j++)
           r(k)[i,j]=r(k-1)[i,j] or (r(k-1)[i,k] and r(k-1)[k,j]);
return r(n);

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


  1. 4
  2. 0 1 0 0
  3. 0 0 0 1
  4. 0 0 0 0
  5. 1 0 1 0

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


     具体代码:

C++语言:
#include
#include
void Warshall(int,int**);
void main()
{
   int i,j,num;
   FILE*p;
   p=fopen("2.txt","r");
   if(p==NULL)
   {
       printf("cannot open 2.txt");
       exit(-1);
   }
   fscanf(p,"%d",&num);
   int **r=(int**)malloc(sizeof(int*)*(num+1));
   for(i=0;i1;i++)
       r[i]=(int*)malloc(sizeof(int)*(num+1));
   for(i=1;i1;i++)
       for(j=1;j1;j++)
           fscanf(p,"%d",&r[i][j]);
   printf("顶点个数为:%d\n",num);
   printf("邻接矩阵为:\n");
   for(i=1;i1;i++)
   {
       for(j=1;j1;j++)
           printf(" %d  ",r[i][j]);
       printf("\n");
   }
   Warshall(num,r);
   printf("最终的传递闭包为\n");
   for(i=1;i1;i++)
   {
       for(j=1;j1;j++)
           printf(" %d  ",r[i][j]);
       printf("\n");
   }

}
//三重循环实现的warshall算法
//r为邻接矩阵,中间存储初试的可达与非可达路径情况,1表示可达,0表示不可达
void Warshall(int num,int**r)
{
   int i,j,k;
   int **temp=(int**)malloc(sizeof(int*)*(num+1));
   for(i=0;i1;i++)
       temp[i]=(int*)malloc(sizeof(int)*(num+1));
   for(k=1;k<=num;k++)//依次取得的可以作为中间点的顶点
   {
       for(i=1;i<=num;i++)
       {
           for(j=1;j<=num;j++)
           {
               temp[i][j]=(r[i][j])||(r[i][k]&r[k][j]);
           }
       }
       for(i=1;i<=num;i++)
           for(j=1;j<=num;j++)
               r[i][j]=temp[i][j];
   }

}


5、结果如下:


  1. 顶点个数为:4
  2. 邻接矩阵为:
  3. 0 1 0 0
  4. 0 0 0 1
  5. 0 0 0 0
  6. 1 0 1 0
  7. 最终的传递闭包为
  8. 1 1 1 1
  9. 1 1 1 1
  10. 0 0 0 0
  11. 1 1 1 1


 

6、参考文献

(1)算法导论

(2)数据结构 严蔚敏

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

阅读(1378) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~