求最小环

floyd求最小环
2011-08-14 9:42

1 定义:

通常来说最小环是针对有向图而言

从一个点出发,经过一条简单路径回到起点成为环.图的最小环就是所有环中长度最小的.

2.怎样求最小环呢?

1传统的解决方法(dijkstra):
        任意一个环的权值,我们都可以看成两个有边相连的结点i、j的直接距离加上i、j间不包含边(边i->j)的最短路径。求最短路径我们第一个想到的就是Dijkstra算法。而Dijkstra所求的是一个点到所有点的最短距离。用Dijkstra所求的i、j的最短距离一定是i、j的直接距离(如果i,j连通),所以我们需要先将i、j的边从图中删除(若i,j不连通,则不用删除),再用Dijkstra求新图中i、j的最短距离即可。所以我们每次在图中选取一条边,把它从图中删掉.然后对删掉的那条边所对应的2点进行Dijkstra,也就是m次Dijkstra。

2.floyd求最小环:

        抛开Dijkstra算法,进而我们想到用Floyd算法。我们知道,Floyd算法在进行时会不断更新矩阵dist(k)。设dist[k,i,j]表示从结点i到结点j且满足所有中间结点,它们均属于集合{1,2,⋯ ,k}的一条最短路径的权。其中dist[0,i,j ]即为初始状态i到j的直接距离。对于一个给定的赋权有向图, 求出其中权值和最小的一个环。我们可以将任意一个环化成如下形式:u->k->v ->(x1-> x2-> ⋯ xm1)-> u(u与k、k与v都是直接相连的),其中v ->(x1-> 2-> ⋯ m)-> u是指v到u不经过k的一种路径。

        在u,k,v确定的情况下,要使环权值最小, 则要求 (x1一>x2->⋯一>xm)->u路径权值最小.即要求其为v到u不经过k的最短路径,则这个经过u,k,v的环的最短路径就是:[v到u不包含k的最短距离]+dist[O,u,k]+dist[O,k,v]。我们用Floyd只能求出任意2点间满足中间结点均属于集合{1,2,⋯ ,k}的最短路径,可是我们如何求出v到u不包含k的最短距离呢?
         现在我们给k加一个限制条件:k为当前环中的序号最大的节点(简称最大点)。因为k是最大点,所以当前环中没有任何一个点≥k,即所有点都(x1->x2->......xm)->u属于当前环,所以x1,x2,⋯ ,xm

3.模板

#include
using namespace std;

const int MAXN=105;
const int INF=10000000;

int dist[MAXN][MAXN],g[MAXN][MAXN];
int fa[MAXN][MAXN],path[MAXN];

int n,m,num,minc;

void Floyd()
{
     int i,j,k,p,tmp;
     minc=INF;
     for(k=1;k<=n;k++)
     {
         for(i=1;i
          for(j=i+1;j
          {
              tmp=dist[i][j]+g[i][k]+g[k][j];
              if(tmp
              {
                  minc=tmp;
                  num=0;
                  p=j;
                  while(p!=i) //逆向寻找前驱结点直到找到最前面的i,i->…->j
                  {
                        path[num++]=p;
                        p=fa[i][p];//fa[i][j]保存的不是k,而是fa[k][j].
                  }
                  path[num++]=i;
                  path[num++]=k;
              }
          }
         for(i=1;i<=n;i++)
          for(j=1;j<=n;j++)
          {
             tmp=dist[i][k]+dist[k][j];
             if(dist[i][j]>tmp)
             {
                 dist[i][j]=tmp;
                 fa[i][j]=fa[k][j];
             }
          }
     }
}

int main()
{
    int i,j,u,v,w;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
          for(i=1;i<=n;i++)
           for(j=1;j<=n;j++)
           {
               g[i][j]=INF;
               dist[i][j]=INF;
               fa[i][j]=i;
           }
          while(m--)
          {
               scanf("%d%d%d",&u,&v,&w);
               w=min(g[u][v],w);          //处理重边
               g[u][v]=g[v][u]=dist[u][v]=dist[v][u]=w;
          }
          Floyd();
          if(minc==INF)
               printf("No solution.\n");
          else
          {
               printf("%d",path[0]);
               for(i=1;i
                   printf(" %d",path[i]);
               printf("\n");
          }
    }
    system("pause");
    return 0;
}

转载于:https://www.cnblogs.com/Yz81128/archive/2012/08/15/2640940.html

你可能感兴趣的:(求最小环)