甲级PAT 1111 Online Map (30 分)(dfs+dijkstra)

1111 Online Map (30 分)

Input our current position and a destination, an online map can recommend several paths. Now your job is to recommend two paths to your user: one is the shortest, and the other is the fastest. It is guaranteed that a path exists for any request.

Input Specification:

Each input file contains one test case. For each case, the first line gives two positive integers N (2≤N≤500), and M, being the total number of streets intersections on a map, and the number of streets, respectively. Then M lines follow, each describes a street in the format:

V1 V2 one-way length time

where V1 and V2 are the indices (from 0 to N−1) of the two ends of the street; one-way is 1 if the street is one-way from V1 to V2, or 0 if not; length is the length of the street; and time is the time taken to pass the street.

Finally a pair of source and destination is given.

Output Specification:

For each case, first print the shortest path from the source to the destination with distance D in the format:

Distance = D: source -> v1 -> ... -> destination

Then in the next line print the fastest path with total time T:

Time = T: source -> w1 -> ... -> destination

In case the shortest path is not unique, output the fastest one among the shortest paths, which is guaranteed to be unique. In case the fastest path is not unique, output the one that passes through the fewest intersections, which is guaranteed to be unique.

In case the shortest and the fastest paths are identical, print them in one line in the format:

Distance = D; Time = T: source -> u1 -> ... -> destination

Sample Input 1:

10 15
0 1 0 1 1
8 0 0 1 1
4 8 1 1 1
3 4 0 3 2
3 9 1 4 1
0 6 0 1 1
7 5 1 2 1
8 5 1 2 1
2 3 0 2 2
2 1 1 1 1
1 3 0 3 1
1 4 0 1 1
9 7 1 3 1
5 1 0 5 2
6 5 1 1 2
3 5

Sample Output 1:

Distance = 6: 3 -> 4 -> 8 -> 5
Time = 3: 3 -> 1 -> 5

Sample Input 2:

7 9
0 4 1 1 1
1 6 1 1 3
2 6 1 1 1
2 5 1 2 2
3 0 0 1 1
3 1 1 1 3
3 2 1 1 2
4 5 0 2 2
6 5 1 1 2
3 5

Sample Output 2:

Distance = 3; Time = 4: 3 -> 2 -> 5

题目要求

导航系统根据给定的起点和终点推荐最适合的路线,有两种推荐方案,一个是行驶距离最短,一个是所用时间最少。

给出n个点(交叉口)和m条路

m条路的表达形式为

[起点 终点 起点和终点是否为单行道 起点和终点的距离 通过起点和终点所用的时间]

每个点的编号从0到n-1

然后按题目给出的格式输出两种推荐方案。如果两种推荐方案的路径相同则按示例2输出,否则按示例1输出

如果行驶距离最短的路径有多条,则输出用时最少的路径

如果所用时间最少的路径有多条,则输出经过的交叉口(结点)最少的

解题思路

这里相当于两个最短路径的问题。。行驶距离最短,所用时间最少。起点到终点,为单源问题,不存在负值,所以用dijksra。

而且这里存在单行道,所以是个有向图的问题。在存储边的时候要注意。

但是发现两个最短路径的思路几乎一模一样,都是用一个weight[i]存储起点到其余点的权值(一个为路径,一个为时间),然后找最小的,再以这个点为中介更新到其他点的距离。。然后一边找最短一边存储同为最短的路径(也就是存储每个结点的上一个结点集合)

只是在dfs的时候有所差别,所以在用结构体保存边的信息的时候直接使用的一个大小为2的数组,到时候在dijkstra算法中直接根据这个下标可以得出每个最短的路径情况

还要注意最后输出的时候要输出最短距离和最短时间为多少,在dijsktra结束之后需要保存一下weight[end]的值

在dfs的时候

行驶距离最短的,根据每条路径的时间之和,找到最小的即可,路径用向量tempans[0]存储

所用时间最短的,直接根据路径中结点的个数,找到最小的即可,路径用向量tempans[1]存储

最后的输出格式只需要判断tempans[0]是否等于tempans[1]

相等,按示例2格式

不等,按示例1格式

注意1格式

1.一定要注意初始化的问题。由于我这里用结构体Edge中用weight的下标来表示不同的信息,在dijkstra的时候共用相同的weight[i[来表示其他点i到起点的权值(距离或者时间),book[i]表示每个点的使用情况,front二维向量来存储每个点的前一个结点。在用下标循环的时候,最开始一定要对它们进行初始化。

for(i=0;i<n;i++) front[i].clear();
for(i=0;i<n;i++){
	weight[i]=edge[start][i].weight[index];
	if(weight[i]!=INF){
		front[i].push_back(start);
	}
}
memset(book,0,sizeof(book));

front不能直接初始化写成front.clear(),这是错误的

2.dfs每次直接先加结点到路径tempans再判断是否到起点了。这样可以把起点也加入到路径中

3.统计路径所用时间注意写法。在遍历路径的时候一定要从起点开始遍历,因为这是单向图,反过来就不行了。而且两节点才是一条路,所以每条路所用时间之和。

for(i=tempans[0].size()-1;i>=1;i--){
	int u=tempans[0][i];
	int v=tempans[0][i-1];
	sum+=edge[u][v].weight[1];
}

4.要注意路径的pop_back()问题。由于这里加入了起点,因此在起点的判断力需要pop_back(),在一个结点所有的前驱结点遍历完也要pop_back()

void dfs(int root,int index){
	tempans[index].push_back(root);
	if(root==start){
		tempans[index].pop_back();
		return;	
	}
	for(i=0;i<front[root].size();i++){
		dfs(front[root][i],index);
	}
	tempans[index].pop_back();
}

如果不加起点可以写成

void dfs(int root,int index){
	if(root==start){
		
		return;	
	}
	tempans[index].push_back(root);
	for(i=0;i<front[root].size();i++){
		dfs(front[root][i],index);
	}
	tempans[index].pop_back();
}

完整代码

#include<bits/stdc++.h>
using namespace std;
#define maxsize 510
#define INF 999999

struct Edge{
	int weight[2]; //length time
}edge[maxsize][maxsize]; 
int n,start,dest;
int weight[maxsize],book[maxsize],minsum[2]={INF,INF};
vector<vector<int> > front(maxsize),ans(2),tempans(2);

void dijskra(int index){
	int i,j,k;
	memset(book,0,sizeof(book));
	book[start]=1;
	for(i=0;i<n;i++){
		int min=INF;
		for(j=0;j<n;j++){
			if(book[j]==0 && min>weight[j]){
				min=weight[j];
				k=j;
			} 
		}
		book[k]=1;
		for(j=0;j<n;j++){
			if(book[j]==0 && edge[k][j].weight[index]!=INF){
				if(weight[j]>weight[k]+edge[k][j].weight[index]){
					weight[j]=weight[k]+edge[k][j].weight[index];
					front[j].clear();
					front[j].push_back(k);
				}else if(weight[j]==weight[k]+edge[k][j].weight[index]){
					front[j].push_back(k);
				} 
			}
		}
	}
}

void dfs(int root,int index){
	int i;
	tempans[index].push_back(root);
	if(root==start){
		if(index==0){
			int sum=0;
			for(i=tempans[0].size()-1;i>=1;i--){
				int u=tempans[0][i];
				int v=tempans[0][i-1];
				sum+=edge[u][v].weight[1];
			}
			if(sum < minsum[0]){
				minsum[0]=sum;
				ans[0] = tempans[0];
			} 	
		}else{
		  int num=tempans[1].size();
			if(num<minsum[1]){
				minsum[1]=num;
				ans[1]=tempans[1];
			}
		}
		tempans[index].pop_back();
		return;	
	}
	for(i=0;i<front[root].size();i++){
		dfs(front[root][i],index);
	}
	tempans[index].pop_back();
}

int main(){
	int m,i,j,k,u,v,oneway,l,t;
	int mindst,mintime;
	scanf("%d %d",&n,&m);
	for(i=0;i<n;i++){
		for(j=0;j<n;j++){
			edge[i][j].weight[0]=edge[i][j].weight[1]=INF;
		}
	} 
	for(i=0;i<m;i++){
		scanf("%d %d %d %d %d",&u,&v,&oneway,&l,&t);
		edge[u][v].weight[0]=l;
		edge[u][v].weight[1]=t;
		if(oneway==0){
			edge[v][u].weight[0]=l;
			edge[v][u].weight[1]=t;
		}
	}
	scanf("%d %d",&start,&dest);
	for(k=0;k<=1;k++){
		for(i=0;i<n;i++) front[i].clear();
		for(i=0;i<n;i++){
			weight[i]=edge[start][i].weight[k];
			if(weight[i]!=INF){
				front[i].push_back(start);
			}
		}
		dijskra(k);
		if(k==0) mindst=weight[dest];
		else mintime=weight[dest];
		dfs(dest,k);
	}
	if(ans[0]==ans[1]){
		printf("Distance = %d; Time = %d: ",mindst,mintime);
		for(i=ans[1].size()-1;i>=0;i--){
			if(i!=ans[1].size()-1) printf(" -> ");
			printf("%d",ans[1][i]);
		}
	}else{
		printf("Distance = %d: ",mindst);
		for(i=ans[0].size()-1;i>=0;i--){
			if(i!=ans[0].size()-1) printf(" -> ");
			printf("%d",ans[0][i]);
		}
		
		printf("\nTime = %d: ",weight[dest]);
		for(i=ans[1].size()-1;i>=0;i--){
			if(i!=ans[1].size()-1) printf(" -> ");
			printf("%d",ans[1][i]);
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值