• Bellman 算法实现


    样例输入:
    7
    0 1 6
    0 2 5
    0 3 5
    1 4 -1
    2 1 -2
    2 4 1
    3 2 -2
    3 5 -1
    4 6 3
    5 6 3
    -1 -1 -1

    样例输出
    1 0→3→2→1
    3 0→3→2
    5 0→3
    0 0→3→2→1→4
    4 0→3→5
    3 0→3→2→1→4→6

    #include <stdio.h>
    #include <string.h>
    #define INF    1000000    //无穷大
    #define MAXN 20        //顶点个数最大值
    
    int n;        //顶点个数
    int Edge[MAXN][MAXN];    //邻接矩阵
    int dist[MAXN];    //
    int path[MAXN];    //
    
    void Bellman( int v0 )    //求顶点v0到其他顶点的最短路径
    {
        int i, j, k, u;        //循环变量
        for( i=0; i<n; i++ )//初始化
        {
            dist[i] = Edge[v0][i];
            if( i!=v0 && dist[i]<INF )  path[i] = v0;
            else path[i] = -1;
        }
        for( k=2; k<n; k++ )    //从dist(1)[u]递推出dist(2)[u], …,dist(n-1)[u]
        {
            for( u=0; u<n; u++ )    //修改每个顶点的dist[u]和path[u]
            {
                if( u != v0 )
                {
                    for( j=0; j<n; j++ )//考虑其他每个顶点
                    {
                        //顶点j到顶点u有直接路径,且途经顶点j可以使得dist[u]缩短
                        if( Edge[j][u] < INF && dist[j] + Edge[j][u] < dist[u] )
                        {
                            dist[u] = dist[j] + Edge[j][u];
                            path[u] = j;
                        }
                    }//end of for
                }//end of if
            }//end of for
        }//end of for
    }
    
    int main( )
    {
        int i, j;    //循环变量
        int u, v, w;    //边的起点和终点及权值
        scanf( "%d", &n );    //读入顶点个数n
        while( 1 )
        {
            scanf( "%d%d%d", &u, &v, &w );    //读入边的起点和终点
            if( u==-1 && v==-1 && w==-1 )  break;
            Edge[u][v] = w;    //构造邻接矩阵
        }
        for( i=0; i<n; i++ )    //设置邻接矩阵中其他元素的值
        {
            for( j=0; j<n; j++ )
            {
                if( i==j ) Edge[i][j] = 0;
                else if( Edge[i][j]==0 )  Edge[i][j] = INF;
            }
        }
        Bellman( 0 );    //求顶点0到其他顶点的最短路径
        int shortest[MAXN];    //输出最短路径上的各个顶点时存放各个顶点的序号
        for( i=1; i<n; i++ )
        {
            printf( "%d	", dist[i] );    //输出顶点0到顶点i的最短路径长度
            //以下代码用于输出顶点0到顶点i的最短路径
            memset( shortest, 0, sizeof(shortest) );
            int k = 0;    //k表示shortest数组中最后一个元素的下标
            shortest[k] = i;
            while( path[ shortest[k] ] != 0 )
            {
                k++; shortest[k] = path[ shortest[k-1] ];
            }
            k++; shortest[k] = 0;
            for( j=k; j>0; j-- )
                printf( "%d→", shortest[j] );
            printf( "%d
    ", shortest[0] );
        }
        return 0;
    }

     用vertor实现Bellman:

    #include<iostream>
    #include<vector>
    using namespace std;
    const int N = 100;
    const int INF = 0x3f3f3f3f;
    
    struct Edge{   //用于记录一组关系
        int u,v,w;
    };
    
    vector<Edge> edge;  //用于保存图的关系
    int dis[N];      //源点到各点的最短距离
    int path[N];     //源点到各点的路径
    int road[N];     //用于逆向追中输出路径
    
    void init(){
        while(!edge.empty()){
            edge.clear();
        }
    }
    
    void Bellman_Ford_vector(int v,int n,int m){   //源点,定点数,边数
        int i,j;
        memset(path,255,sizeof(path));   //初始化路径为-1;
        for(i=0;i<=n;i++){               //初始化dis[i]为不可到达
            dis[i] = INF;
        }
        dis[v] = 0;      //把源点到自己的路径改为0
    
        for(i=0;i<n;i++){  //第一层循环,由dis0递推出dis1~n
            for(j=0;j<m;j++){  //判断边<u,v>的引入能否缩短源点到v的距离
                if(dis[edge[j].u] + edge[j].w < dis[edge[j].v]){ //若可以松弛,更新
                     dis[edge[j].v] = dis[edge[j].u] + edge[j].w;
                     path[edge[j].v] = edge[j].u;
                }
            }
        }
    }
    
    int main(){
        freopen("in.txt","r",stdin);
        int n;
        Edge temp;
        while(scanf("%d",&n)!=EOF){
            init();
            while(scanf("%d%d%d",&temp.u,&temp.v,&temp.w) && ~temp.u && ~temp.v && ~temp.w){
                edge.push_back(temp);  //把关系添加到vector
            }
            Bellman_Ford_vector(0,n,edge.size());
    
            for(int i=1;i<n;i++){
                printf("%d	",dis[i]);  //输出最短路
    
                int k=0;               //用于标记要经过几个点
                road[k] = i;           //保存第一个点
                while(path[road[k]] != -1){//若还有前继点,逆向追踪
                    k++;
                    road[k] = path[road[k-1]];
                }
                while(k){              //输出路径
                    printf("%d->",road[k--]);
                }
                printf("%d
    ",road[k]);
            }
        }
        return 0;
    }
                
  • 相关阅读:
    阅读笔记--- 04
    站立会议--06个人进度
    站立会议--05 个人
    站立会议---04个人
    场景分析
    站立会议---03个人
    站立会议---02 个人进度
    计算某一天距离今天多少天,多少小时,多少分钟
    改变图片颜色
    手动调整导航控制器中的viewcontroller
  • 原文地址:https://www.cnblogs.com/Deng1185246160/p/3223236.html
Copyright © 2020-2023  润新知