算法导论:Bellman-Ford算法以及基于拓扑排序的有向无环图单源最短路径问题

1. Bellman-Ford算法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
实现c/c++代码如下:

/**
Initialize-single-source(G,s):
    for each vertex v in V:
        v.d <- OO
        v.p <- NIL
    s.d <- 0

Relax(u,v):
    if u.d + w(u,v) < v.d:
        v.d <- u.d + w(u,v)
        v.p <- u

Bellman-Ford(G,w,s):
    Initialize-Single-Source(G,s):
    for i <-1 to |V| -1:
        for each edge(u,v) in E:
            relax(u,v)
    for each edge(u,v) in E:
        if v.d > u.d + w(u,v):
            return false
    return true
**/

#include<stdio.h>
#include<iostream>
#include<vector>
#include<set>
using namespace std;

const int MAX = 0xffff;

struct vertex {
    int d;
    int p;
};

vertex points[101];
vector<int> vs[101];
set<int> se;
set<pair<int,int> >bian;
int dist[101][101];
void init(int s){
    for(set<int>::iterator it=se.begin();it!=se.end();it++){
        int te = *it;
        points[te].d = MAX;
        points[te].p = -1;
    }
    points[s].d = 0;
}

void relax(int u,int v){
    if(points[v].d > points[u].d + dist[u][v] ){
        points[v].d = points[u].d + dist[u][v];
        points[v].p = u;
    }
}

bool bellman_ford(int s){
    init(s);
    int len = se.size()-1;
    while(len--){
        for(set<pair<int,int> >::iterator it= bian.begin();it!=bian.end();it++){
            pair<int,int> tp = *it;
            relax(tp.first,tp.second);
        }
    }

    for(set<pair<int,int> >::iterator it= bian.begin();it!=bian.end();it++){
            pair<int,int> tp = *it;
            if(points[tp.second].d > points[tp.first].d+dist[tp.first][tp.second]){
                return false;
            }
    }

    return true;

}
//author:GUET_diadestiny
int main(){

    int n;//边数
    cin>>n;
    while(n--){
        int a,b,val;
        cin>>a>>b>>val;
        dist[a][b] = val;
        vs[a].push_back(b);
        se.insert(a);
        se.insert(b);
        bian.insert(make_pair(a,b));
    }
    if(!bellman_ford(0)){
        cout<<"存在负权环路"<<endl;
    }
    for(set<int>::iterator it=se.begin();it!=se.end();it++){
        int te = *it;
        cout<<te<<"  "<<points[te].p <<"  "<<points[te].d<<endl;
        //输出从源点0到任意一点te的最短路径距离points[te].d;
    }
    return 0;
}
//输入有向图测试数据(边数,从i指向j的权值val):
//8
//0 1 6
//0 4 7
//1 4 8
//4 3 9
//4 2 -3
//1 3 -4
//1 2 -2
//3 2 7

2. 基于拓扑排序的有向无环图单源最短路径问题

在这里插入图片描述

/**
dag-shortest-paths(G,w,s):
    topologically sort the vertices of G:
    Initialize-Single-Source(G,s)
    for each vertex u taken in topologically sorted order:
        for each edge(u,v) in E:
            relax(u,v)
**/
#include<iostream>
#include<vector>
#include<stdio.h>
#include<set>
#include <stdlib.h>
#define WHITE -1
#define GREY 0
#define BLACK 1
using namespace std;

struct Node{
    int data;
    struct Node * next;
};

struct vertex{
    int color;
    int parent;
    int final_time;
    int first_time;
    int d;
};

const int MAX = 0xffff;

vector<int> vs[101];//存储边的邻接表
vertex points[101];
set<int> se;//记录所有顶点编号
int time = 0;
Node* headlink = NULL;
int dist[101][101];



void init(int s){
    for(set<int>::iterator it=se.begin();it!=se.end();it++){
        int te = *it;
        points[te].d = MAX;
        points[te].parent = -1;
    }
    points[s].d = 0;
}

void relax(int u,int v){
    if(points[v].d > points[u].d + dist[u][v] ){
        points[v].d = points[u].d + dist[u][v];
        points[v].parent = u;
    }
}



void head_insert(int t){
    Node * tp = (Node*)malloc(sizeof(Node));
    tp->data = t;
    tp->next = headlink->next;
    headlink->next = tp;
}

void print_link(){
    Node *ph = headlink->next;
    while(ph){
        cout<<ph->data<<" ";
        ph = ph->next;
    }
    cout<<endl;
}

void dfs_visit(int u,vertex& p){
    time++;
    p.first_time = time;
    p.color = GREY;
    for(int i=0;i<vs[u].size();i++){
        int te = vs[u][i];
        if(points[te].color == WHITE){
            points[te].parent = u;
            dfs_visit(te,points[te]);
        }
    }
    p.color = BLACK;
    time = time + 1;
    p.final_time = time;
    head_insert(u);
}

void topsort_dfs(){
    set<int>::iterator it = se.begin();
    for(it=se.begin();it!=se.end();it++){
        points[*it].color = WHITE;
        points[*it].parent = -1;
    }
    for(it=se.begin();it!=se.end();it++){
        int t = *it;
        if(points[t].color == WHITE){
            dfs_visit(t,points[t]);
        }
    }
}

void dag_shortpath(){
    topsort_dfs();
    init(0);
    Node *ph = headlink->next;
    while(ph){
        int data = ph->data;
        for(int i=0;i<vs[data].size();i++){
            relax(data,vs[data][i]);
        }
        ph = ph->next;
    }

}

//author:GUET_diadestiny
int main()
{
    headlink = (Node*)malloc(sizeof(Node));
    headlink->next = NULL;
    int n;//边数
    cin>>n;
    while(n--){
        int a,b,val;
        cin>>a>>b>>val;
        dist[a][b] = val;
        vs[a].push_back(b);
        se.insert(a);
        se.insert(b);
    }
    dag_shortpath();//基于topsort的有向无环图的单源最短路径问题(时间复杂度为O(V+E))
    print_link(); //输出一个拓扑排序序列

    for(set<int>::iterator it=se.begin();it!=se.end();it++){
        int te = *it;
        cout<<te<<"  "<<points[te].parent <<"  "<<points[te].d<<endl;
        //输出从源点0到任意一点te的最短路径距离points[te].d;

    }
	return 0;
}


//输入有向图测试数据(边数,从i指向j的权值val):
//8
//0 1 6
//0 4 7
//1 4 8
//4 3 9
//4 2 -3
//1 3 -4
//1 2 -2
//3 2 7
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值