Loading

「清新题精讲」UVA 1048 - Low Cost Air Travel

UVA 1048 - Low Cost Air Travel

\(\mathsf{\color{Thistle}{Statement}}\)

给定 \(n\) 张机票和 \(q\) 次旅行,每张机票都给出飞机所经过的城市,每一次乘座飞机,必须从飞机的起始站开始,且中途不能乘坐其他飞机再回来乘坐该架飞机,但是可以提前离开飞机。

对于第 \(i\) 次旅行,输出一次经过给定城市所需的最小代价。

\(\mathsf{\color{Thistle}{Solution}}\)

如果计算相邻 \(2\) 个城市之间的最小花费并累计,显然是不对的,因为可能相邻 \(3\) 个城市在一条航程上。

故,考虑 \((i,j)\) 表示走过了前 \(i\) 个给定城市,当前位于 \(j\)。那么,以该二元组建图后,再跑最短路即可。对于 \((i,j)\) 这个点,枚举可能所在的航道,以及在该航道飞至第几个城市,对于所有可能连边建图即可。

举个例子:「样例 \(1\)\((1,1)\rightarrow (2,3),(1,1)\rightarrow (2,4),(1,1)\rightarrow (1,2)\dots\)

这样,对于 \(1\) 条边,其实便等价于 \(1\) 次换乘,所以边权也是显而易见的,时间复杂度:\(O(qn^4l)\),其中 \(l\) 为查询路径的长度。

注意:输出方案的时候,末尾不能有多余的空格✨。

\(\mathsf{\color{Thistle}{Code}}\)

#include <bits/stdc++.h>
#define fi first
#define se second
#define int long long

using namespace std;

typedef pair<int, int> PII;
typedef pair<int, PII> PIII;
typedef long long LL;

const int N = 25;

int n, q, l;
struct route {
	int w;
	std::vector<int> city;
}rt[N];
std::map<PII, vector<PIII>> g;
std::map<PII, int> st;
std::map<PII, pair<PII, PII>> dist;

void dijkstra(PII start) {
	priority_queue<PIII, vector<PIII>, greater<PIII>> heap;
	dist.clear(), st.clear(), heap.push({0, start}), dist[start] = {{0, 0}, start};
	while (heap.size()) {
		auto u = heap.top();
		heap.pop();

		if (st.count(u.se)) continue;
		st[u.se] = 1;

		for (auto v : g[u.se]) {
			heap.push({u.fi + rt[v.fi].w, v.se});
			if (!dist.count(v.se)) dist[v.se] = {{u.fi + rt[v.fi].w, v.fi}, u.se};
			else if (u.fi + rt[v.fi].w < dist[v.se].fi.fi) dist[v.se] = {{u.fi + rt[v.fi].w, v.fi}, u.se};
		}
	}
}

signed main() {
	cin.tie(0);
	cout.tie(0);
	ios::sync_with_stdio(0);

	int cs = 0;
	while (cin >> n && n) {
		set<int> pnt;
		for (int i = 1; i <= n; i ++) {
			cin >> rt[i].w >> l, rt[i].city.resize(l + 1);
			for (int j = 1; j <= l; j ++)
				cin >> rt[i].city[j], pnt.insert(rt[i].city[j]);
		}

		cin >> q, cs ++;
		for (int trip = 1; trip <= q; trip ++) {
			cin >> l;
			std::vector<int> path(l + 1);
			for (int i = 1; i <= l; i ++)
				cin >> path[i];
			for (int i = 1; i < l; i ++)
				for (auto v : pnt) {
					for (int j = 1; j <= n; j ++)
						if (rt[j].city[1] == v) {
							int tmp = i;
							for (int k = 2; k < rt[j].city.size(); k ++) {
								if (tmp < l && rt[j].city[k] == path[tmp + 1]) tmp ++;
								g[{i, v}].push_back({j, {tmp, rt[j].city[k]}});
							}
						}
				}
			dijkstra({1, path[1]});
			cout << "Case " << cs << ", Trip " << trip << ": Cost = " << dist[{l, path[l]}].fi.fi << endl;
			PII End = {l, path[l]};
			std::vector<int> way;
			while (End != make_pair(1ll, path[1])) {
				way.push_back(dist[End].fi.se);
				End = dist[End].se;
			}
			reverse(way.begin(), way.end());
			cout << "  Tickets used: ";
			for (int i = 0; i < way.size(); i ++) {
				if (i == way.size() - 1) cout << way[i];
				else cout << way[i] << " ";
			}
			cout << endl;
			g.clear();
		}
	}

	return 0;
}
posted @ 2024-06-19 14:48  E-Syrus  阅读(3)  评论(0编辑  收藏  举报