PAT | A1111 Online Map

2次Dijkstra
一定要好好看题鸭哭哭,看到在最短距离相同时选择最快的路,就想当然的认为在最短时间相同时选择最短的路,会导致测试点2错误。

#include <iostream>
#include <vector>
#include <climits>
#include <algorithm>

using namespace std;

int L[510][510];
int T[510][510];
int preL[510];
int preT[510];
int len[510];
int tim[510];
int thoughCitiesForMinT[510];
int timForMinL[510];
bool vis[510];

void DijkstraL(int s,int n){
	fill(preL,preL + 510,-1);
	fill(len,len + 510,INT_MAX);
	fill(timForMinL,timForMinL + 510,INT_MAX);
	fill(vis,vis + 510,false);
	len[s] = 0;
	timForMinL[s] = 0;
	for(int i = 0;i < n;i++){
		int u = -1,MINL = INT_MAX,MINT = INT_MAX;
		for(int j = 0;j < n;j++){
			if(vis[j] == false && (len[j] < MINL || (len[j] == MINL && timForMinL[j] < MINT))){
				u = j;
				MINL = len[j];
				MINT = timForMinL[j];
			}
		}
		if(u == -1) return;
		vis[u] = true;
		for(int v = 0;v < n;v++){
			if(vis[v] == false && L[u][v] != INT_MAX && (len[u] + L[u][v] < len[v] || (len[u] + L[u][v] == len[v] && timForMinL[u] + T[u][v] < timForMinL[v]))){
				len[v] = len[u] + L[u][v];
				timForMinL[v] = timForMinL[u] + T[u][v];
				preL[v] = u;
			}
		}
	}
}

void DijkstraT(int s,int n){
	fill(preT,preT + 510,-1);
	fill(tim,tim + 510,INT_MAX);
	fill(thoughCitiesForMinT,thoughCitiesForMinT + 510,INT_MAX);
	fill(vis,vis + 510,false);
	tim[s] = 0;
	thoughCitiesForMinT[s] = 0;
	for(int i = 0;i < n;i++){
		int u = -1,MINT = INT_MAX,MINL = INT_MAX;
		for(int j = 0;j < n;j++){
			if(vis[j] == false && (tim[j] < MINT || (tim[j] == MINT && thoughCitiesForMinT[j] < MINL))){
				u = j;
				MINT = tim[j];
				MINL = thoughCitiesForMinT[j];
			}
		}
		if(u == -1) return;
		vis[u] = true;
		for(int v = 0;v < n;v++){
			if(vis[v] == false && T[u][v] != INT_MAX && (tim[u] + T[u][v] < tim[v] || (tim[u] + T[u][v] == tim[v] && thoughCitiesForMinT[u] + 1 < thoughCitiesForMinT[v]))){
				tim[v] = tim[u] + T[u][v];
				thoughCitiesForMinT[v] = thoughCitiesForMinT[u] + 1;
				preT[v] = u;
			}
		}
	}
}

int main(){
	int n,m;
	scanf("%d %d",&n,&m);
	// n : 城市个数
	// m : 道路条数
	for(int i = 0;i < 510;i++){
		for(int j = 0;j < 510;j++){
			L[i][j] = INT_MAX;
			T[i][j] = INT_MAX;
		}
	}
	for(int i = 0;i < m;i++){
		int v1,v2,oneWay,l,t;
		scanf("%d %d %d %d %d",&v1,&v2,&oneWay,&l,&t);
		if(oneWay == 1){ // 是v1->v2单行道
			L[v1][v2] = l;
			T[v1][v2] = t;
		}else{ // 是双行
			L[v1][v2] = l;
			L[v2][v1] = l;
			T[v1][v2] = t;
			T[v2][v1] = t;
		}
	}
	int source,destination;
	scanf("%d %d",&source,&destination);
	DijkstraL(source,n);
	DijkstraT(source,n);
	int d = destination;
	vector<int> minLength;
	while(preL[d] != -1){
		if(minLength.size() != 0){
			minLength.insert(minLength.begin(),d);
		}else{
			minLength.push_back(d);
		}
		d = preL[d];
	}
	if(minLength.size() != 0){
		minLength.insert(minLength.begin(),d);
	}else{
		minLength.push_back(d);
	}
	d = destination;
	vector<int> minTime;
	while(preT[d] != -1){
		if(minTime.size() != 0){
			minTime.insert(minTime.begin(),d);
		}else{
			minTime.push_back(d);
		}
		d = preT[d];
	}
	if(minTime.size() != 0){
		minTime.insert(minTime.begin(),d);
	}else{
		minTime.push_back(d);
	}
	int lenL = minLength.size(),lenT = minTime.size();
	bool sameRoad = true;
	if(lenL != lenT)
		sameRoad = false;
	else{
		for(int i = 0;i < lenL;i++){
			if(minLength[i] != minTime[i]){
				sameRoad = false;
				break;
			}
		}
	}
	if(sameRoad == true){
		printf("Distance = %d; Time = %d:",len[destination],tim[destination]);
		for(int i = 0;i < lenL;i++){
			printf(" %d",minLength[i]);
			if(i != lenL - 1)
				printf(" ->");
		}
	}else{
		printf("Distance = %d:",len[destination]);
		for(int i = 0;i < lenL;i++){
			printf(" %d",minLength[i]);
			if(i != lenL - 1)
				printf(" ->");
		}
		printf("\nTime = %d:",tim[destination]);
		for(int i = 0;i < lenT;i++){
			printf(" %d",minTime[i]);
			if(i != lenT - 1)
				printf(" ->");
		}
	}
	system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值