算法训练 最短路
时间限制:1.0s 内存限制:256.0MB
问题描述
给定一个n个顶点,m条边的有向图(其中某些边权可能为负,但保证没有负环)。请你计算从1号点到其他点的最短路(顶点从1到n编号)。
输入格式
第一行两个整数n, m。
接下来的m行,每行有三个整数u, v, l,表示u到v有一条长度为l的边。
输出格式
共n-1行,第i行表示1号点到i+1号点的最短路。
样例输入
3 3
1 2 -1
2 3 -1
3 1 2
1 2 -1
2 3 -1
3 1 2
样例输出
-1
-2
-2
数据规模与约定
对于10%的数据,n = 2,m = 2。
对于30%的数据,n <= 5,m <= 10。
对于100%的数据,1 <= n <= 20000,1 <= m <= 200000,-10000 <= l <= 10000,保证从任意顶点都能到达其他所有顶点。
Bellman—ford算法
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int MAX = 0x3f3f3f3f; int v[500005], u[500005]; //起点,终点 int w[500005]; //权值 int n, m; //顶点数,边数 int d[20005]; //路径数组 void bellman(int s){ memset(d, MAX, sizeof(d)); d[s] = 0; //必须初始化这个 int flag = 1; for(int k = 0; k < n - 1; k++){ flag = 1; for(int i = 0; i < m; i++){ //遍历每一条边 if(d[u[i]] > d[v[i]] + w[i]){//如果这条边的终点的d[]值小于起始点的d[]值加上这条边的权值,则更新d d[u[i]] = d[v[i]] + w[i]; flag = 0; } } if(flag){ break; } } } int main(){ int ss; while(scanf("%d%d", &n, &m) == 2){ for(int i = 0; i < m; i++){ scanf("%d%d%d", &v[i], &u[i], &w[i]); } int s, e; // scanf("%d%d", &s, &e); // bellman(s); // if(d[e] < MAX){ // printf("%d ", d[e]); // } // else{ // printf("-1 "); // } bellman(1); for(int i = 2; i <= n; i++){ printf("%d ", d[i]); } } return 0; }
spfa算法:
#include <iostream> #include <cstring> #include <cstdio> #include <queue> #include <vector> using namespace std; const int MAX = 0x3f3f3f3f; vector <int>v1[20005]; //v1[i]表示i到的终点 vector <int>v2[20005]; //v2[i]表示i和v1[i]的边的权值 int visit[20005]; //表示是否已经在队列里面 int d[20005]; int n, m, ss; void spfa(int ss){ memset(d, 0x3f, sizeof(d)); d[ss] = 0; queue <int>mq; mq.push(ss); visit[ss] = 1; while(!mq.empty()){ int x = mq.front(); mq.pop(); visit[x] = 0; for(int i = 0; i < v1[x].size(); i++){ int v = v1[x][i]; int len = v2[x][i]; if(d[v] > d[x] + len){ d[v] = d[x] + len; if(visit[v] == 0){ //这个在上一个if里面,只有别更新了,才有可能影响其他点,才放入队列 mq.push(v); visit[v] = 1; } } } } } int main(){ while(cin >> n >> m){ memset(visit, 0, sizeof(visit)); memset(v1, 0, sizeof(v1)); memset(v2, 0, sizeof(v2)); int x, y, z; for(int i = 0; i < m; i++){ cin >> x >> y >> z; // if(z < v2[x][y]){ //两个点多条路,去最短的 v2[x].push_back(z); //压入权值 v1[x].push_back(y); //压入x的另一个顶点 // } } int end; spfa(1); // for(int i = 1; i <= n; i++){ // if(d[i] < MAX){ // cout << d[i] << " "; // } // else{ // cout << 2147483647 << " "; // } // } for(int i = 2; i <= n; i++){ printf("%d ", d[i]); } } return 0; }