ACM中的图中关于最短路径的dijistra算法和bellman_ford算法

本文详细介绍了Dijkstra算法与Bellman-Ford算法的原理及应用场景,前者适用于求解无负权边的最短路径问题,后者则能处理包含负权边的情况,并能检测是否存在负权环。通过具体实例演示了两种算法的实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

dijistra算法是求从源点s开始到其他点的最短路径问题。前提条件是带权值的边。权值为正数。

1.将每个点的距离设为无穷大,彼此都不连通。将这些点的集合设为S.

2.另一个集合为V。从源点s开始,距离设为0,放到集合V中。

3.设每条边是<u,v>。则通过dist(v) = min{dis(v),dist(u) + l(u,v)} 进行松弛操作。选取最小代价的点,放到集合V中,知道集合S中的元素被拿光结束。

注意:编码时可以通过数组 visited 来对两个集合进行区分。


bellman_ford算法可以计算权值为负数。需要判断负权环。

负权环是某点存在环路,且dist值还不断减少,这样,最小值是不存在的。所以这种情况这个点是不存在最短路径的。

1.将每个点距离设为无穷大。

2.循环n-1次,n为点数。 每次循环遍历每条边,进行松弛操作 dist(v) = min{dis(v),dist(u) + l(u,v)},边是<u,v>。重复的计算知道所有边得到正确的距离代价。

3.检查负权环。如果还存在可以松弛的话,则存在负权环。此步骤相当于举反例证明最短路径不存在。

dijistra算法例子:

 The K-th City

Given a map of your country, there are N cities. The cities are labeled as 0, 1, ..., N - 1, and you live in city 0. Can you calculate out the K-th nearest city form you? If two or more cities have the same distance form you, you may assume that the city with smaller label is nearer than the city with bigger one.

Input

There are several cases. The first line of each case is two integers N and M (1 ≤ N ≤ 200, 0 ≤ M ≤ 10000), which is the number of cities in your country and the total number of roads in your country. There are three integers in each of the following M lines, ABC, which descript one road. A and B are the two cities that connected by that road, and C is the length of that road (1 ≤ C ≤ 2000). The roads are of both directions, and no two roads connect two same cities. There is at least one path between any two cities. At the last line of each case is a single integer K (1 ≤ K < N).

The last case is followed by a line with a single 0.

Output

Print the label of the K-th nearest city.

Sample Input

4 3
0 1 120
0 2 180
1 3 40
3
4 3
0 1 120
0 3 60
3 2 30
1
0

Sample Output

2
3

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define INF 0x1f1f1f1f
using namespace std;
int graph[250][250];
int distant[250];//short path
int previous[250];//record the previous nodes of the edge
int visited[250];
int m;//vertexs
int n;//edges
void Dijkstra(int k) {
    int i;
    int j;
    int l;

    for(i = 0; i < m; i ++) {
        distant[i] = INF;
    }

    distant[0] = 0;
    memset(visited, 0, sizeof(visited));
    //visited[0] = 1;


    for(i = 0; i < m; i++) {
        int mind = INF;
        int position;//short distant position
        for(j = 0; j < m; j++){
            if(!visited[j] && distant[j] < mind){
                position = j;
                mind = distant[j];
            }
        }

        if(i == k) {
            cout<<position<<endl;
            break;
        }

        visited[position] = 1;

        for(l = 0; l < m; l++) {
            if(!visited[l] && (distant[l] > distant[position] + graph[position][l])){
                distant[l] = distant[position] + graph[position][l];
            }
        }
    }
}

int main() {
    while(cin>>m && m >0) {
        cin>>n;
        int i,j;
        for(i = 0; i < m; i++){
            for(j = 0; j < m; j++){
                if(i == j) {
                    graph[i][j] = 0;
                } else {
                    graph[i][j] = INF;
                }
            }
        }

        for(i = 0; i < n; i++) {
            int from;
            int to;
            int weight;
            cin>>from>>to>>weight;
            graph[from][to] = weight;
            graph[to][from] = weight;
            //undirected graph
        }

        int k;
        cin>>k;
        Dijkstra(k);
    }
    return 0;
}


bellman_ford算法例子

TOJ 2831.   Wormholes


#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define INF 0x1f1f1f1f
#define MAX 10000
using namespace std;
typedef struct {
    int from;
    int to;
    int weight;
}Edge;
Edge edge[MAX];

int n;//the sum of nodes
int m;
int w;
int sum_edge;//= 2 * m + w;
int dist[MAX];
bool bellman_ford() {
    int i;
    int j;
    for(i = 1; i <= n; i++) {
        dist[i] = INF;
    }
    bool relaxation = false;
    for(i = 1; i < sum_edge; i++) {
        for(j = 1; j <= sum_edge; j++) {
            if(dist[edge[j].to] > dist[edge[j].from] + edge[j].weight) {
                dist[edge[j].to] = dist[edge[j].from] + edge[j].weight;
                relaxation = true;
            }
        }

        if(relaxation == false)
            break;
    }

     for(j = 1; j <= sum_edge; j++) {
        if(dist[edge[j].to] > dist[edge[j].from] + edge[j].weight) {
           return true;
        }
    }

    return false;
}

int main() {
    int i;
    int f;
    cin>>f;

    while(f--) {
        cin>>n>>m>>w;
        sum_edge = 2 * m + w;

        int from;
        int to;
        int weight;
        int num = 1;

        for(i = 0; i < m; i++) {
            cin>>from>>to>>weight;
            edge[num].from = from;
            edge[num].to = to;
            edge[num].weight = weight;
            num++;
            edge[num].from = to;
            edge[num].to = from;
            edge[num].weight = weight;
            num++;
        }

        for(i = 0; i < w; i++) {
            cin>>from>>to>>weight;
            edge[num].from = from;
            edge[num].to = to;
            edge[num].weight = - weight;
            num++;
        }

        if(bellman_ford()) {
            cout<<"YES"<<endl;
        } else {
            cout<<"NO"<<endl;
        }
    }

    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值