# Dijkstra# Priority Queue# Graph# Shortest Path

g733 - 110北二4.漫遊高譚市

🔗 前往 ZeroJudge 原題

題目描述

題目描述一個城市的地圖,包含兩種交通方式:步行和搭乘蝙蝠車。地圖由 n 個地點和 m1 個步行路徑、m2 個蝙蝠車路徑組成。要求計算從起點 s 到終點 t 的最短路徑長度,可以任意切換步行和蝙蝠車。

解題思路

本題可以使用 Dijkstra 演算法來求解最短路徑。由於存在兩種交通方式,因此需要為每個節點維護四個狀態:dis[node][0] 表示只使用步行到達該節點的最短路徑長度,dis[node][1] 表示步行和蝙蝠車交替到達該節點的最短路徑長度,dis[node][2] 表示從步行轉蝙蝠車到達該節點的最短路徑長度,dis[node][3] 表示只使用蝙蝠車到達該節點的最短路徑長度。

Dijkstra 演算法使用優先佇列來選擇下一個要擴展的節點,優先佇列按照路徑長度排序。在擴展節點時,需要考慮兩種交通方式,並更新相應狀態下的最短路徑長度。

複雜度分析

  • 時間複雜度: O(E log V),其中 E 是邊的數量,V 是節點的數量。
  • 空間複雜度: O(V),用於儲存距離陣列和優先佇列。

程式碼

#include <bits/stdc++.h>
using namespace std;
int n,m1,m2,x,y,v,s,t,dis[10005][4];
bool has[10005][4];
vector <pair <int,int>> E1[100005],E2[100005];//go dis
void djsk(){
	priority_queue <pair <int,pair <int,int>>,vector <pair <int,pair <int,int>>>,greater <pair <int,pair <int,int>>>> pq;//dis by go
	for(int i=0;i<4;++i){
		pq.push({0,{i,s}});
		dis[s][i]=0;
	}
	while(!pq.empty()){
		int dt=pq.top().first,by=pq.top().second.first,g=pq.top().second.second;
		pq.pop();
		if(has[g][by])continue;
		has[g][by]=1;
		if(by!=3){//0 1 2
			for(int i=0;i<E1[g].size();++i){
				if(by==1){
					if(dis[E1[g][i].first][2]>dis[g][by]+E1[g][i].second){
						dis[E1[g][i].first][2]=dis[g][by]+E1[g][i].second;
						pq.push({dis[E1[g][i].first][2],{2,E1[g][i].first}});
					}
				} 
				else{
					if(dis[E1[g][i].first][by]>dis[g][by]+E1[g][i].second){
						dis[E1[g][i].first][by]=dis[g][by]+E1[g][i].second;
						pq.push({dis[E1[g][i].first][by],{by,E1[g][i].first}});
					}
				}
			}
		}
		if(by!=2){//0 1 3
			for(int i=0;i<E2[g].size();++i){
				if(by==0){
					if(dis[E2[g][i].first][3]>dis[g][by]+E2[g][i].second){
						dis[E2[g][i].first][3]=dis[g][by]+E2[g][i].second;
						pq.push({dis[E2[g][i].first][3],{3,E2[g][i].first}});
					}
				} 
				else{
					if(dis[E2[g][i].first][by]>dis[g][by]+E2[g][i].second){
						dis[E2[g][i].first][by]=dis[g][by]+E2[g][i].second;
						pq.push({dis[E2[g][i].first][by],{by,E2[g][i].first}});
					}
				}
			}
		}
	}
}
int main(){
	cin.tie(0); ios::sync_with_stdio(false);
	cin >> n >> m1 >> m2;
	memset(dis,0x3f,sizeof(dis));
	for(int i=0;i<m1;++i){
		cin >> x >> y >> v;
		E1[x].push_back({y,v});
		E1[y].push_back({x,v});
	}
	for(int i=0;i<m2;++i){
		cin >> x >> y >> v;
		E2[x].push_back({y,v});
		E2[y].push_back({x,v});
	}
	cin >> s >> t;
	djsk();
	cout << min(min(dis[t][0],dis[t][1]),min(dis[t][2],dis[t][3]));
}

Discussion