PAT甲级A1030答案(使用C语言)

题目描述

A traveler’s map gives the distances between cities along the highways, together with the cost of each highway. Now you are supposed to write a program to help a traveler to decide the shortest path between his/her starting city and the destination. If such a shortest path is not unique, you are supposed to output the one with the minimum cost, which is guaranteed to be unique.

Input Specification:

Each input file contains one test case. Each case starts with a line containing 4 positive integers N, M, S, and D, where N (≤500) is the number of cities (and hence the cities are numbered from 0 to N−1); M is the number of highways; S and D are the starting and the destination cities, respectively. Then M lines follow, each provides the information of a highway, in the format:

City1 City2 Distance Cost

where the numbers are all integers no more than 500, and are separated by a space.

Output Specification:

For each test case, print in one line the cities along the shortest path from the starting point to the destination, followed by the total distance and the total cost of the path. The numbers must be separated by a space and there must be no extra space at the end of output.

Sample Input:

4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20

Sample Output:

0 2 3 3 40

题目要求

1.这道题是一道跟图有关的题目,给出节点和权值,求最短路径
2.但是这道题不是求最短路径那么简单,除了每条路径的长度之外,还有每条路需要消耗的物资,所以这里要设置另外一个矩阵来存放消耗量

解题步骤

1.在Dijkstra的基础上加上一个存放cos的矩阵,即为消耗量矩阵,由于最后还要输出整个路径,所以要有一个存放路径的数组来存放路径上每个点的上一个节点,然后用DFS算法输出路径上的每个节点

int dis[MAXV][MAXV]; //存放路径权值的矩阵
int cos[MAXV][MAXV]; //存放消耗量的矩阵
int pre[MAXV]; //存放路径节点的数组
int n, m, d[MAXV], c[MAXV], start, desn;

2.由于这里要选的最短路径不仅路径要最短,消耗也要最短,这里就会出现路径相等但是消耗不等的情况,所以我们要做的就是在路径相等时选择消耗最短的路径,这里就是需要在原始Dijkstra中加上的判断条件

for(int i = 0; i < n; i++){
		int u = -1, MIN = INF;
		for(int j = 0; j < n; j++){
			if(vis[j] == false && d[j] < MIN){
				MIN = d[j];
				u = j;
			}
		}
		if(u == -1) return;
		//pre[u] = s;
		vis[u] = true;
		for(int v = 0 ; v < n; v++){
			//这种是所有路径不等的情况,只需要找到路径权值最短的即可
			if(vis[v] == false && dis[u][v] != INF && d[v] > dis[u][v] + d[u]){
				d[v] = d[u] + dis[u][v];
				pre[v] = u;
				c[v] = c[u] + cos[u][v];
			}
			//这种是存在路径权值相等的情况,所以还需要比较消耗量的大小,在相等的路径中选出消耗量最小的路径
			else if(vis[v] == false && dis[u][v] != INF && d[v] == dis[u][v] + d[u] && c[v] > c[u] + cos[u][v]){
				pre[v] = u;
				c[v] = c[u] + cos[u][v];
			}
		}
	} 

完整代码

#include<stdio.h>
#include<algorithm>
using namespace std;
const  MAXV = 1000;
const  INF = 1000000;
int dis[MAXV][MAXV], cos[MAXV][MAXV], pre[MAXV];
int n, m, d[MAXV], c[MAXV], start, desn;
bool vis[MAXV] = {false};

void dijkstra(int s){
	fill(d, d + MAXV, INF);
	//fill(c, c + MAXV, 0);
	d[s] = 0; //改错加
	
	for(int i = 0; i < n; i++){
		int u = -1, MIN = INF;
		for(int j = 0; j < n; j++){
			if(vis[j] == false && d[j] < MIN){
				MIN = d[j];
				u = j;
			}
		}
		if(u == -1) return;
		//pre[u] = s;
		vis[u] = true;
		for(int v = 0 ; v < n; v++){
			if(vis[v] == false && dis[u][v] != INF && d[v] > dis[u][v] + d[u]){
				d[v] = d[u] + dis[u][v];
				pre[v] = u;
				c[v] = c[u] + cos[u][v];
			}
			else if(vis[v] == false && dis[u][v] != INF && d[v] == dis[u][v] + d[u] && c[v] > c[u] + cos[u][v]){
				pre[v] = u;
				c[v] = c[u] + cos[u][v];
			}
		}
	}
}


void DFS(int v){//深度优先遍历输出最短路径
    if(v == start)
        printf("%d ",v);
    else{
        DFS(pre[v]);
        printf("%d ",v);
    }
}

int main(){
	int u, v, w, cost;
	fill(cos[0], cos[0] + MAXV * MAXV, INF);
	fill(dis[0], dis[0] + MAXV * MAXV, INF);
	fill(pre, pre + MAXV, 0);
	scanf("%d%d%d%d", &n, &m, &start, &desn);
	for(int i = 0; i < m; i++){
		scanf("%d%d%d%d", &u, &v, &w, &cost);
		//无向图一定要注意这里
		dis[u][v] = dis[v][u] = w;
		cos[u][v] = cos[v][u] = cost;
	}
	//dijkstra(start, G1, pre1);
	dijkstra(start);
	/*
	for(int k = 2; k < desn+1; k++){
		printf("%d ", pre[k]);
	}*/
	DFS(desn);
	printf("%d %d", d[desn], c[desn]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值