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\t", 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\n", 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\t",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\n",road[k]);
        }
    }
    return 0;
}
            

 

转载于:https://www.cnblogs.com/Deng1185246160/p/3223236.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值