机场快线(Airport Express,UVA 11374)

       机场快线分为经济线和商业线两种。有一张商业线车票,其他时候只能乘经济线。你的任务是找一条去机场最快的线路。

我们可以枚举商业线的哪一站,假设我们用商业线车票从车站A坐到车站B,则从起点到a,从a到终点这两部分路线对于“经济线网络”来说都应该是最短路。用Dijkstra可以列出两点之间的所有最短路,以及统计最短路的条数。

#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;

const int INF=1000000000;
const int maxn=500+10;

struct Edge{
	int from,to,dist;
};

struct HeapNode{       //Dijkstra算法用到的优先队列的结点
	int d,u;
	bool operator < (const HeapNode& rhs)const{
		return d>rhs.d;
	}
};

struct Dijkstra{
	int n,m;                //点数和边数
	vector<Edge> edges;     //边列表
	vector<int> G[maxn];    //每个结点出发的边编号(从0开始编号)
	bool done[maxn];        //是否已永久标号
	int d[maxn];            //s到各个点的距离
	int p[maxn];            //最短路中的上一条弧

	void init(int n){
		this->n=n;
		for(int i=0;i<n;i++) G[i].clear();//清空邻接表
		edges.clear();
	}
	void AddEdge(int from,int to,int dist){
		//如果是无向图,每条无向边需调用两次AddEdge
		Edge edge={from,to,dist};
		edges.push_back(edge);
		m=edges.size();
		G[from].push_back(m-1);
	}
	
	void dijkstra(int s){
		priority_queue<HeapNode> Q;
		for(int i=0;i<n;i++) d[i]=INF;
		d[s]=0;
		memset(done,0,sizeof(done));
		HeapNode heapnode={0,s};
		Q.push(heapnode);
		while(!Q.empty()){
			HeapNode x=Q.top();Q.pop();
			int u=x.u;
			if(done[u]) continue;
			done[u]=true;
			for(int i=0;i<G[u].size();i++){
				Edge& e=edges[G[u][i]];
				if(d[e.to]>d[u]+e.dist){
					d[e.to]=d[u]+e.dist;
					p[e.to]=G[u][i];
					HeapNode heapnode={d[e.to],e.to};
				    Q.push(heapnode);
				}
			}
		}
	}
	//dist[i]为s到i的距离,path[i]为s到i的最短路径(经过的结点列表,包括s和t)
	void GetShortestPaths(int s,int* dist,vector<int>* paths){
		dijkstra(s);
		for(int i=0;i<n;i++){
			dist[i]=d[i];
			paths[i].clear();
			int t=i;
			paths[i].push_back(t);
			while(t!=s){
				paths[i].push_back(edges[p[t]].from);
				t=edges[p[t]].from;
			}
			reverse(paths[i].begin(),paths[i].end());
		}
	}
};

//题目相关
Dijkstra solver;
int d1[maxn],d2[maxn];
vector<int> paths1[maxn],paths2[maxn];

int main(){
	int kase=0,N,S,E,M,K,X,Y,Z;
	while(cin>>N>>S>>E>>M){
		solver.init(N);
		S--;E--;//编号从0~N-1
		for(int i=0;i<M;i++){
			cin>>X>>Y>>Z;X--;Y--;
			solver.AddEdge(X,Y,Z);
			solver.AddEdge(Y,X,Z);
		}
		solver.GetShortestPaths(S,d1,paths1);//S到所有点的距离和路径
		solver.GetShortestPaths(E,d2,paths2);//T到所有点的距离和路径
		
		int ans=d1[E];               //初始解解为直达距离
		vector<int> path=paths1[E];  //初始解的station序列
		int midpoint=-1;             //不坐商业线
		cin>>K;
		for(int i = 0; i < K; i++) {
			cin>>X>>Y>>Z; X--; Y--;
			for(int j = 0; j < 2; j++) { // j=0代表商业线坐X->Y,j=1代表Y->X
				if(d1[X] + d2[Y] + Z < ans) {
					ans = d1[X] + d2[Y] + Z;
					path = paths1[X];
					for(int j = paths2[Y].size()-1; j >= 0; j--) // 从Y到T的距离要反过来
						path.push_back(paths2[Y][j]);
					midpoint = X;
				}
				swap(X, Y);
			}
		}
		if(kase!=0) cout<<endl;
		kase++;
		for(int i=0;i<path.size()-1;i++) cout<<path[i]+1<<" ";
		cout<<E+1<<endl;
		if(midpoint==-1) cout<<"Ticket Not Used"<<endl;
		else cout<<midpoint+1<<endl;
		cout<<ans<<endl;
	}
	return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值