数模论坛

 找回密码
 注-册-帐-号
搜索
热搜: 活动 交友 discuz
查看: 31913|回复: 45

图论方面的算法设计 (荐)

[复制链接]
发表于 2003-7-2 10:09:22 | 显示全部楼层 |阅读模式
写在前面:
很多人说这个版的内容太深了,开始时偶帖了97年A题的编程交流,确实那道问题有点难,下面偶还是贴一些基础的好一些。

大家都知道图论方法对建模竞赛来说很重要,比如98年B题和00年B题。都涉及到了网络规划方面的问题。下面针对最短路径的算法来进行讨论,大家可以踊跃来发言,也可以谈谈如何对这种问题来进行编程设计,如果可以针对98年B题和00年B题的更好。
发表于 2003-7-2 19:09:19 | 显示全部楼层

这方面的程序比较麻烦,写出来不难,就是调不过
最后不知道改了什么地方,就通过了
有时候真的很FT
 楼主| 发表于 2003-7-3 07:28:17 | 显示全部楼层

我觉得象图论方面的编程最好自己准备一个库函数,或者干脆就写一个图论类就行了。
最短路的算法:Dijkstra算法、Floyd算法是一定要准备的。
发表于 2003-7-17 04:01:17 | 显示全部楼层

能提供一点实用程序交流吗?
发表于 2003-7-19 21:23:28 | 显示全部楼层

不明白楼主的意思,最短路径的算法太过普遍了,虽然思想很重要,但是毕竟现在的实用问题远非求解最短路径那么简单。
我做过的图论问题,很多都是在自己逐步的算例演算中发现、总结定理和规则,然后加以证明,再逐渐推广的。
 楼主| 发表于 2003-7-20 05:46:08 | 显示全部楼层

程序我已经封装起来了,没法再单独做一个。
最短径问题的算法非常普遍,采用了动态规划的思想,这种思想特别重要,很多实际问题规模往往是NP难的,比如次短路径,或带限制的路径问题,很多问题可以归结为不等式规划问题,楼上说也很有道理,“很多都是在自己逐步的算例演算中发现...”,要单独去发现一些性质,关键在于知道基本的算法,写出基本的程序,这也是偶发此贴的目的了。
发表于 2003-7-22 21:47:17 | 显示全部楼层

有时偶写一些程序与只是程序中的片段,
要写一个完整的还得用到很的库函数
如果没有呢,那怎么办??
发表于 2003-7-23 23:54:53 | 显示全部楼层

图论方法主要就是kruskal,prin和Guan mei Gu的算法啦!
发表于 2003-7-24 03:33:39 | 显示全部楼层

看来我这位计算机专业的学生还有很多没有学到,我也要加强学习
Dijkstra算法、Floyd算法
kruskal,prin和Guan mei Gu的算法
 楼主| 发表于 2003-7-24 06:26:55 | 显示全部楼层

偶帖一下一位大牛人starfish写的图论代码吧,
他在2000年获得全国数模竞赛的一等奖,是个比偶强N倍的人物。
/**********************************************                                             *
*              图论算法                       *
*                                             *
*                   copyright starfish        *
*                           2000/10/24        *
*                                             *
\*********************************************/

#define infinity 1000000      // a big int
#define max_vertexes 50       // the max count of vertexes

typedef int Graph[max_vertexes][max_vertexes];   // use adjacent matrix to represent graph

/*********************************************
         求最小生成树的Prim算法
         用邻接矩阵表示图,复杂度为O(n^2)
         参数G表示图的邻接矩阵,
         vcount表示图的顶点个数,
         father用来记录每个节点的父节点
**********************************************/
void prim(Graph G,int vcount,int father[])
{
   int i,j,k;
   int lowcost[max_vertexes], closeset[max_vertexes], used[max_vertexes];
   for( i = 0; i < vcount; i++ )
   {
      lowcost = G[0];
      closeset = 0;        // notice: here vertex 1 is G[0]
      used = 0;            // mark all vertexes have not been used
      father = -1;         // that means no father
   }
   used[0] = 1;               // mark vertex 1 has been used
   for( i=1; i< vcount; i++)
   {
      j=0;
      while( used[j] ) j++;
      for(k=0; k<vcount; k++)
         if ( ( !used[k] ) && ( lowcost[k] < lowcost[j] ) )
         {
            j=k;              // find the next tree edge
         }
      father[j]=closeset[j];  // record the tree edge using father array
      used[j]=1;              // mark vertex j+1 has been used
      for (k=0;k<vcount;k++)
         if (!used[k]&&(G[j][k]<lowcost[k]))  // modify the lowcost
         {  
             lowcost[k]=G[j][k];
             closeset[k]=j;  
         }
   }
}

/*===============================================

                单源最短路径

                Dijkstra 算法

            适用条件:所有边的权非负

            !!注意:
            1.输入的图的权必须非负
            2.顶点标号从0开始
            3.当i,j不相邻时G[i,j]=infinity

================================================*/
int Dijkstra(Graph G,int n,int s,int t, int path[])
{
    int i,j,w,minc, d[max_vertexes], mark[max_vertexes];
    for (i=0; i<n; i++) mark=0;

    for (i=0; i<n; i++)
    {   
        d=G;
        path=s;  
    }
   
    mark=1; path=0; d=0;

    for(i=1; i<n; i++)
    {   
        minc = infinity;
        w = 0;
        for( j = 0; j < n; j++ )
          if( ( mark[j]==0 ) && ( minc >= d[j] ) ) {
            minc=d[j];w=j;
          }
        mark[w]=1;
        for(j=0; j<n; j++)
          if( (mark[j]==0) && ( G[w][j] != infinity ) && ( d[j] > d[w]+G[w][j] ) )
            {   
               d[j]=d[w]+G[w][j];
               path[j]=w;     
            }
   }
   return d[t];
}

/*======================================================

      单源最短路径

   Bellman-Ford 算法

适用条件:所有情况,边权可以为负
G为图,n为图的节点数目,s,t分别为源点和终点,
success用来标示该函数是否成功,
如果存在一个从源点可达的权为负的回路则success=false;
返回值为s,t之间的最短路径长度;


            !!注意:
            1.顶点标号从0开始
            2.当i,j不相邻时G[i,j]=infinity

=============================================================*/

int Bellman_Ford(Graph G,int n,int s,int t,int path[],int success)
{
   int i,j,k,d[max_vertexes];
   for (i=0;i<n;i++) {
       d=infinity;
       path=0;
   }
   d=0;
   for (k=1;k<n;k++)
     for (i=0;i<n;i++)
       for (j=0;j<n;j++)
         if( d[j] > d+G[j] ) {
             d[j] = d+G[j];
             path[j] = i;
         }
   success=0;

   for (i=0;i<n;i++)
     for (j=0;j<n;j++)
       if( d[j] > d+G[j] ) return 0;

   success=1;
   return d[t];
}

/*==========================================

              每对节点间最短路径
                Floyd-Warshall 算法

    D[i,j]表示从i到j的最短距离;
    P[i,j]表示从i到j的最短路径上j 的父节点

===========================================*/

void Floyd_Washall(Graph G,int n,Graph D,Graph P)
{
    int i,j,k;
    for (i=0;i<n;i++)
        for (j=0;j<n;j++) {   
            D[j] = G[j];
            P[j] = i;      
        }
    for (i=0;i<n;i++) {  
        D = 0;
        P = 0;
    }

    for (k=0;k<n;k++)
        for (i=0;i<n;i++)
            for (j=0;j<n;j++)
                if ( D[j] > D[k] + D[k][j] ) {  
                    D[j] = D[k] + D[k][j];
                    P[j] = P[k][j];
                 }
}
您需要登录后才可以回帖 登录 | 注-册-帐-号

本版积分规则

小黑屋|手机版|Archiver|数学建模网 ( 湘ICP备11011602号 )

GMT+8, 2024-11-27 05:41 , Processed in 0.231337 second(s), 19 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表