首页 > 代码库 > 九度OJ刷题——1008:最短路径问题

九度OJ刷题——1008:最短路径问题

题目描述:
给你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

这题要注意两点,第一个是可能会存在重边,当两点之间存在重边的时候,存储长度最短的那条,如果有多条最短边,则取费用最低的那条边;第二个是最大值MAX的设置,一开始我设置的是INT_MAX,结果一直WA,因为INT_MAX与其他正值相加后会溢出成为负值,使得判定条件出错,这个一定要多加小心。

源代码:
#include <iostream>
#include <cstring>
using namespace std;

const int N = 1001;
const int MAX = 1 << 30;
int dm[N][N];
int pm[N][N];
int minDis, minCost;

void dijkstra(int s, int t, int n);

int main(){
	int n, m;
	while(cin >> n >> m){
		if(n==0 && m==0) break;

		//初始化距离矩阵和费用矩阵
		for(int i=1; i<=n; i++){
			for(int j=1; j<=n; j++){
				dm[i][j] = MAX;
				pm[i][j] = MAX;
			}
		}
		for(int i=0; i<m; i++){
			int a, b, d, p;
			cin >> a >> b >> d >> p;
			//这两个判断条件是为了处理重边
			if(dm[a][b] > d){
				dm[a][b] = dm[b][a] = d;
				pm[a][b] = pm[b][a] = p;
			}
			else if(dm[a][b]==d && pm[a][b]>p){
				pm[a][b] = pm[b][a] = p;
			}
		}
		int s, t;
		cin >> s >> t;
		dijkstra(s, t, n);
		cout << minDis << ‘ ‘ << minCost << endl;
	}
	
	//system("pause");

	return 0;
}

void dijkstra(int s, int t, int n){
	//存储点s到各点的距离和费用
	int dis[N];
	int cost[N];
	for(int i=1; i<=n; i++){
		dis[i] = MAX;
		cost[i] = MAX;
	}
	//用于判断是否已经求出s点到某点的最短距离和费用
	bool visit[N];
	memset(visit, false, sizeof(visit));
	//点s到自己的距离和费用为0
	dis[s] = 0;
	cost[s] = 0;
	for(int i=0; i<n; i++){
		int min = MAX;
		int k;
		for(int j=1; j<=n; j++){
			if(!visit[j] && dis[j]<min){
				min = dis[j];
				k = j;
			}
		}
		visit[k] = true;

		for(int j=1; j<=n; j++){
			if(!visit[j] && dis[j]>min+dm[k][j]){
				dis[j] = min + dm[k][j];
				cost[j] = cost[k] + pm[k][j];
			}
			else if(!visit[j] && dis[j]==min+dm[k][j] && cost[j]>cost[k]+pm[k][j]){
				cost[j] = cost[k] + pm[k][j];
			}
		}
	}
	minDis = dis[t];
	minCost = cost[t];
}

  

九度OJ刷题——1008:最短路径问题