版权声明:本博全为博主学习日常,均为原创,请勿转载 https://blog.csdn.net/weixin_44332298/article/details/88085921
时间限制:1s 内存限制:128MB
题目描述
n个节点m条边,每条边都有长度d和花费p,给出起点S和终点T,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。
输入
输入n,m,点的编号是1~n,然后m行,每行4个数。a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行为两个数,S,T,S为起点,T为终点。n和m为0时输入结束。(1 < n <= 1000,0 < m < 100000,S != T)
输出
输出一行有两个数:最短距离及其花费。
样例输入
3 2
1 2 5 6
2 3 4 5
1 3
0 0
样例输出
9 11
代码
#include <iostream>
#include <vector>
using namespace std;
struct E { //邻接链表元素结构体
int next;
int c;
int cost;
};
vector<E> edge[1001]; //邻接链表
int Dis[1001]; //距离数组
int cost[1001]; //花费数组
bool mark[1001]; //是否属于集合k数组
int main() {
int n, m; //n个点m条边
int S, T; //起点,终点
while(cin >> n >> m) {
if(n==0 && m==0) {
break;
}
for(int i = 1; i <= n; i++) {
edge[i].clear();
}
while(m--) {
int a, b, c, cost;
cin >> a >> b >> c >> cost;
E tmp;
tmp.c = c;
tmp.cost = cost;
tmp.next = b;
edge[a].push_back(tmp);
tmp.next = a;
edge[b].push_back(tmp);
}
cin >> S >> T;
for(int i = 1; i <= n; i++) {
Dis[i] = -1;
mark[i] = false;
}
Dis[S] = 0;
mark[S] = true;
int newP = S; //起点为S,将其加入集合K,且其最短距离确定为0
for(int i = 1; i < n; i++) { //循环n-1次
for(int j = 0; j < edge[newP].size(); j++) { // 遍历与该新加入集合k中节点直接相邻的边
int t = edge[newP][j].next;
int c = edge[newP][j].c;
int co = edge[newP][j].cost;
if(mark[t] == true)
continue;
if(Dis[t]==-1 || Dis[t]>Dis[newP]+c || Dis[t]==Dis[newP]+c && cost[t]>cost[newP]+co) {
//比较大小时,将距离相同但花费更短也作为更新条件之一
Dis[t] = Dis[newP]+c;
cost[t] = cost[newP]+co; //更新花费
}
}
int min = 123123123;
for(int j = 1; j <= n; j++) { //遍历所有节点
if(mark[j] == true) //若属于集合k则跳过
continue;
if(Dis[j] == -1) //若该节点仍不可达则跳过
continue;
if(Dis[j] < min) { //若该点经由节点1至集合k中的某点在经过一条边到达时距离小于当前最小值
min = Dis[j]; //更新为最小值
newP = j; //新加入的点暂定为该点
}
}
mark[newP] = true;
}
cout << Dis[T] << " " << cost[T] << endl;
}
return 0;
}