题目描述:
给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。
Input
输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点。n和m为0时输入结束。
(1<n<=1000, 0<m<100000, s != t)
Output
输出 一行有两个数, 最短距离及其花费。
Sample Input
3 2
1 2 5 6
2 3 4 5
1 3
0 0
Sample Output
9 11
code:
#include<cstdio>
#include<iostream>
#include<string.h>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 1010;
struct node
{
long long int len;
long long int cost;
}nodes[maxn][maxn];
long long int m, n, a, b, d, p, s, t;
long long int dis[maxn], spend[maxn], book[maxn];
int main()
{
while(cin>>n>>m && n && m)
{
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
nodes[i][j].len = inf;
nodes[i][j].cost = 0;
}
nodes[i][i].cost = 0;
nodes[i][i].len = 0;
}
memset(dis, 0x3f, sizeof dis);
memset(book, 0, sizeof book);
for(int i = 1; i <= m; i++)
{
scanf("%lld%lld%lld%lld", &a, &b, &d, &p);
if(nodes[a][b].len > d)
{
nodes[a][b].len = nodes[b][a].len = d;
nodes[a][b].cost = nodes[b][a].cost = p;
}
else if(nodes[a][b].len == d && nodes[a][b].cost < p)
nodes[a][b].cost = nodes[b][a].cost = p;
}
scanf("%lld%lld", &s, &t);
for(int i = 1; i <= n; i++)
{
dis[i] = nodes[s][i].len;
spend[i] = nodes[s][i].cost;
}
book[s] = 1;
/* for(int i = 1; i <= n; i++)
{
cout<<"a:"<<dis[i]<<" "<<spend[i]<<endl;
} */
for(int i = 1; i <= n-1; i++)
{
int minNode, min = inf;
for(int j = 1; j <= n; j++)
{
if(book[j] == 0 && dis[j] < min)
{
minNode = j;
min = dis[j];
}
}
//cout<<"a: "<<min<<endl;
book[minNode] = 1;
for(int j = 1; j <= n; j++)
{
if(book[j]==0 && min+nodes[minNode][j].len < dis[j] || (min+nodes[minNode][j].len == dis[j] && spend[i]+nodes[minNode][j].cost < spend[j]))
{
dis[j] = min+nodes[minNode][j].len;
spend[j] = spend[minNode]+nodes[minNode][j].cost;
}
}
}
printf("%lld %lld\n", dis[t], spend[t]);
}
return 0;
}
小结:题目和描述都很清楚,就是带权图求最短路,再次学习了求最短路的算法,感觉暑假学的并不很清楚,这次终于搞懂了。
- floyd算法,分别以每个点a[k]作为任两点a[i],a[j]的中间点,以此不断松弛,最终得到所有点间的最短路,时间复杂度为O(n³)。
- dijkstra算法,进行n-1次松弛,每次找出距起点最近的且未松驰过的点,然后以该点作为中间点进行松弛,最终求出其它各个顶点距起点的最短路,时间复杂度为O(n²),同时写法上也有邻接矩阵和邻接链表两种。
- bellman-ford算法,分别记录每条边的起点和终点,根据边的权值找出各个点距起点的最短路,时间复杂度O(n*m),同时可以找出图中是否含有负边,并且还可以优化时间复杂度。
至于这些算法的进阶使用,只有慢慢挖掘了,对了,这道题有个坑就是可能相同顶点间可能有多条边,输入时要进行判断,还有自己在网上看到的博客:
最短路算法1
最短路算法2