PAT甲级 1111 Online Map(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

dijkstra算法中 dis[ i ]数组(Time) 不仅仅是 start -> i点的最短距离 而是 在更新(找到满足题意条件的最短距离)dis数组时完成

满足题意条件的距离(eg: 距离最短且用时最少 等等(多个维度条件))重新得到dis[ i ]

本题思路:1.求出给定 指定路径距离最短路径(时间最短)

                  2.求出给定 指定时间最短路径(路径顶点数最少)

                   因此用两次dijkstra算法 求出满足题意条件的路径

                  在求最短距离时,如果存在相同的最短距离,需要找到用时最短的那条:

                 

if(dis[u]+edge[u][k]==dis[k] && w[k]>weight[u][k] + w[u]){ //当存在到start点相同的最短路径且到达的时间比此时在w[k](记录到start到k点需要用的时间)中的更短 
					w[k] = weight[u][k] + w[u]; //将start到k点所用的最短路径时间更新
					dispre[k] = u;      //直接更新到达k点的父节点为u 	

              在求用时最少的(fast路径)距离时,如果存在相同的最快路径,需要找到路径结点最少的那条:

	}else if(Time[u]+weight[u][k]==Time[k] && node[k] > node[u] + 1){  //当k到达start存在两条时间相同的路线且此时结点数小于之前路径的结点数 
					node[k]=node[u]+1;//更新结点数
					Timepre[k]=u;	  //更新到达k的父节点为u 
				}

 

具体代码

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int inf = 0x3f3f3f;
const int maxsize = 520;
int n,m;
int from,to,flag,length,time;      // flag==0表from ->to 与to->from都是联通的, length为道路长度边权值,time为走完道路用时边权值      
int start,endll;                   //start为规定的开始结点,endll为指定到达的结点 end是特殊字  endl也是特殊字 
//weight[i][j]存放的是i->j 需要用的时间,w[i]表示start到i点(满足题意条件)路径所需要的时间,node[i]存放的start到i点(满足题意条件)路径的全部结点(顶点) 
int dis[maxsize],Time[maxsize],edge[maxsize][maxsize],weight[maxsize][maxsize],w[maxsize],node[maxsize]; 
int Timepre[maxsize],dispre[maxsize]; //dispre[i]=u 表到u的最短路径的最近结点为u  TimePre[i] = u 同样如此 
bool visit[maxsize]; 
vector<int> dispath; //存放长度最短路径且(长度最短路径中时间最短)的路径
vector<int> Timepath;//存放时间最短且(时间最短路径中路径结点数最少)的路径 
void Timedfs(int end){//因为路径存放在数组Timepre中 通过dfs 找到 满足 题意(start->end)的所有结点 将结点送入timepath 
//	cout<<"end 是 "<<end<<" pre[end] 是"<< Timepre[end]<<endl; 
	if(end==Timepre[end]){
		Timepath.push_back(end); 
		return;	
	}
	Timedfs(Timepre[end]);
	Timepath.push_back(end);
	
}
void disdfs(int end){ //因为路径存放在数组dispre中 通过dfs 找到满足题意(start->end)的所有结点 将结点送入dispath 
	cout<<"end 是 "<<end<<" pre[end] 是"<< dispre[end]<<endl; 
	if(end==dispre[end]){
		dispath.push_back(end);
		return;
	}
	disdfs(dispre[end]);
	dispath.push_back(end);
	
}
void disdijkstra(int start){
	dis[start]=0;
	for(int i=0;i<n;i++){
		int min=inf,u=-1;
		for(int j=0;j<n;j++){
			if(dis[j]<min && visit[j]==false){
				min=dis[j];
				u=j;
			}
		}
		if(min==inf) return;
		visit[u]=true; 
		for(int k=0;k<n;k++){
			if(edge[u][k]!=inf && visit[k] == false){
				if(dis[u]+edge[u][k] < dis[k]){
					dis[k] = dis[u] + edge[u][k];//k点存在到start点更近的道路 更新dis[k] 
					w[k] = weight[u][k] + w[u]; //将start到k点所用的最短路径时间更新
					dispre[k] = u;      //直接更新到达k点的父节点为u 
				}else if(dis[u]+edge[u][k]==dis[k] && w[k]>weight[u][k] + w[u]){ //当存在到start点相同的最短路径且到达的时间比此时在w[k](记录到start到k点需要用的时间)中的更短 
					w[k] = weight[u][k] + w[u]; //将start到k点所用的最短路径时间更新
					dispre[k] = u;      //直接更新到达k点的父节点为u 					
				}
			}
		}
	}
}
void Timedijkstra(int start){
	Time[start]=0;
	for(int i=0;i<n;i++){
		int min=inf,u=-1;
		for(int j=0;j<n;j++){
			if(Time[j]<min && visit[j] == false){
				min=Time[j];
				u=j;
			}
		}
		visit[u]=true;
		if(min==inf) return;
		for(int k=0;k<n;k++){                      //
			if(visit[k]==false && weight[u][k]!=inf){
				if(Time[u]+weight[u][k] < Time[k]){//当此时k到达start的点存在更短的时间 
					Time[k]=Time[u] + weight[u][k]; //更新此时k点到start的时间 
					node[k]=node[u]+1;              //此时从start到k的结点个数为 u的结点个数+1 
					Timepre[k]=u;					//更新到达k的父节点为u
				}else if(Time[u]+weight[u][k]==Time[k] && node[k] > node[u] + 1){  //当k到达start存在两条时间相同的路线且此时结点数小于之前路径的结点数 
					node[k]=node[u]+1;//更新结点数
					Timepre[k]=u;	  //更新到达k的父节点为u 
				}
			}
		}	
		
	}
}

void init_path_num(int n){
	for(int i=0;i<n;i++){
		dispre[i]=i;
		Timepre[i]=i;
	}	
}

int main(){
	scanf("%d%d",&n,&m);
	init_path_num(n);       //初始化存储路径的数组 dispre[n] timepre[n]
	fill(edge[0],edge[0]+maxsize*maxsize,inf);
	fill(dis,dis+maxsize,inf);
	fill(weight[0],weight[0]+maxsize*maxsize,inf);
	fill(Time,Time+maxsize,inf); 
	for(int i=0;i<m;i++){
		scanf("%d%d%d%d%d",&from,&to,&flag,&length,&time);
		edge[from][to] = length;
		weight[from][to] = time; 
		if(flag!=1){
			edge[to][from]=length;
			weight[to][from]=time;
		}
	}
	scanf("%d%d",&start,&endll);
	disdijkstra(start);            //第一次使用dijkstra算法,得到路径最短(用时最短)的路径 
//	//测试dis[n]中具体的值
//	for(int i=0;i<sizeof(dis)/sizeof(int);i++){
//		cout<<"dis 数组中的值为"<<dis[i]<<endl;
//	} 
//	//测试Time[n]中具体的值
	for(int i=0;i<sizeof(Time)/sizeof(int);i++){
		cout<<"Time 数组中的值为"<<Time[i]<<endl;
	} 
	fill(visit,visit+maxsize,false);//第二次使用dijkstra算法,得到fast得到用时最短(结点数最多)的路径 
	Timedijkstra(start);
	disdfs(endll);
	Timedfs(endll);
	printf("Distance = %d",dis[endll]);
//	printf("\nTime = %d: ",Time[endll]);
	if(dispath==Timepath){
		printf("; Time = %d: ",Time[endll]);
		for(int i=0;i<dispath.size();i++){
			if(i!=0)
				printf(" -> ");
			printf("%d",dispath[i]);
		}
	}else{
		printf(": ");
		for(int i=0;i<dispath.size();i++){
			if(i!=0)
				printf(" -> ");
			printf("%d",dispath[i]);
		}
		printf("\n");
		printf("Time = %d: ",Time[endll]);
		for(int i=0;i<Timepath.size();i++){
			if(i!=0)
				printf(" -> ");
			printf("%d",Timepath[i]);
		}
		
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值