Uva 11374机场快线 最短路(枚举一条边)

该博客介绍了Uva 11374题目的解决方案,讨论了一种在包含经济线和只能走一次的商业线的图中寻找起点到终点最短路径的方法。通过预处理起点和终点的最短路,并枚举商业线,计算结合商业线后的最短路径,从而找到全局最短路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意

在一张图中有两种路线,一种是经济线,一种是商业线,经济线可以随便走,但是商业线只能走一次。现在问从起点到终点的最短路是什么。

题解

预处理起点和终点最短路。
设起点为S,终点为E。
枚举每一条商业线(u,v),现在需要快速知道S->u的最短路径,v->E的最短路径,这样就可以得出选这条商业线的最短路。解决的办法是预处理,以起点和终点分别开始跑一遍最短路,得出数组d1[i],d2[j]。那么选择商业线(u,v,w)的最短路径就是d1[u]+w+d2[v]
枚举每一条商业线取最小即可。

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 500+5;
const int INF = 0x3f3f3f3f;
#define to second
#define co first
typedef pair<int, int> pii;

vector<pii> G[maxn];
int n,S,E;
int d1[maxn];
int d2[maxn];
int path[maxn];
void solve(int s, int d[]) {
	memset(path,0, sizeof path);
	for(int i = 0; i <= n; ++i)
		d[i] = INF;
	d[s] = 0;
	priority_queue<pii,vector<pii>, greater<pii> > que;
	que.push(pii(d[s],s));
	while(!que.empty()) {
		pii u = que.top();
		que.pop();
		if(d[u.second] < u.first) 
			continue;
		int x = u.second;
		// cout << x << endl;
		for(int i = 0; i < G[x].size(); ++i) {
			pii &e = G[x][i];
			if(d[e.to] > d[x]+e.co) {
				d[e.to] = d[x]+e.co;
				que.push(pii(d[e.to],e.to));
				path[e.to] = x;
			}
		}
	}
}
void find() {
	queue<pii> que;
	que.push(pii(d1[S],S));	
	while(!que.empty()) {
		pii u = que.front();
		que.pop();
		int x = u.second;
		// cout << x << endl;
		for(int i = 0; i < G[x].size(); ++i) {
			pii &e = G[x][i];
			if(d1[e.to] == d1[x]+e.co) {
				d1[e.to] = d1[x]+e.co;
				que.push(pii(d1[e.to],e.to));
				path[e.to] = x;
			}
		}
	}
}
void add(int u,int v,int c) {
	G[u].push_back(pii(c,v));
}

int main() {
	// freopen("in.txt","r",stdin);
	int kas = 0;
	while(~scanf("%d", &n)) {
		if(kas)
			puts("");
		kas++;
		for(int i = 0; i <= n; ++i)
			G[i].clear();
		scanf("%d%d", &S,&E);
		int m;
		scanf("%d", &m);
		for(int i = 0; i < m; ++i) {
			int u,v,c;
			scanf("%d%d%d",&u,&v,&c);
			add(u,v,c);add(v,u,c);
		}
		solve(S,d1);
		solve(E,d2);
		// for(int i = 1; i <= n; ++i)
		// 	cout << d1[i] << " " ;
		// cout << endl;
		int k;
		scanf("%d", &k);
		int _dis = d1[E];
		int au = -1,av = -1,ac = -1;
		for(int i = 0; i < k; ++i) {
			int u,v,c;
			scanf("%d%d%d",&u,&v,&c);
			for(int j = 0; j < 2; ++j) {
				int tmp = d1[u]+d2[v]+c;
				if(tmp < _dis) {
					_dis = tmp;
					au = u, av = v, ac = c;
				}
				swap(u,v);
			}

		}
		if(au != -1) {
			add(au,av,ac);
			add(av,au,ac);
		}
		solve(S,d1);
		stack<int> p;
		int x = E;
		while(x) {
			p.push(x);
			x = path[x];
		}
		while(!p.empty()) {
			int u = p.top();
			p.pop();
			if(p.empty())
				printf("%d\n", u);
			else 
				printf("%d ", u);
		}
		if(au != -1)
			printf("%d\n", au);
		else 
			puts("Ticket Not Used");
		printf("%d\n", _dis);

	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值