UVA10816 Travel in Desert

知识点:最短瓶颈路,最小生成树,深搜

本题要求出起点和终点的最短瓶颈路,如果有多个求出其中最短路,最短瓶颈路就是两个点之间的简单路径的最大边权最小的路,它的求解可以用最小生成路来进行,求出最小生成树了,那么树上两点之间的路径就是最短瓶颈路,路径上边权的最大值就是我们要求的,这里可能有多个,所以我们先用最小生成树求出最短瓶颈路的值,然后在去求最短瓶颈路里面最短的,这里一看数据是100,就用了深搜去求最短路,效果还不错,但是一开始又犯了一个低级的错误,那就是没有个无向边的数组大小开够,浪费了快20分钟,然后这里其实就是只求了一对点最短瓶颈路的最大边长,如果要每一对点的就用个深搜记录搜索一下就行了

跑了40ms,还可以,要知道这还是在所有点建的边上跑的,并没有把不可能是最短瓶颈路的边给删掉

需要注意的是,输入的是先温度后距离,输出的时候是先距离后温度

#include <bits/stdc++.h>

using namespace std;

const int N = 105, M = 2e4 + 5;

struct edge {
	int u, v;
	double t, d;
	edge() {}
	edge(int a, int b, double x, double y): u(a), v(b), t(x), d(y) {}
};

int n, m, s, t, fa[N], vis[N];
int tot, ver[M], nxt[M], head[N];
double ans_t, ans_d, edge_t[M], edge_d[M];
edge e[N * N];
vector<int> v, ans;

void add(int x, int y, double z1, double z2) {
	ver[++tot] = y;
	edge_t[tot] = z1; edge_d[tot] = z2;
	nxt[tot] = head[x]; head[x] = tot;
}

int get(int x) {
	if (x == fa[x]) return x;
	return fa[x] = get(fa[x]);
}

bool cmp(edge a, edge b) {
	return a.t < b.t;
}

void dfs(int x, double dist) {
	if (dist >= ans_d) return;
	vis[x] = 1; v.push_back(x);
	if (x == t) {
		ans_d = dist;
		ans = v;
		vis[x] = 0; v.pop_back();
		return;
	}
	for (int i = head[x]; i; i = nxt[i]) {
		int y = ver[i];
		if (!vis[y] && edge_t[i] <= ans_t) dfs(y, dist + edge_d[i]);
	}
	vis[x] = 0; v.pop_back();
}

int main() {
	while (cin >> n >> m) {
		tot = 0;
		memset(head, 0, sizeof(head));
		cin >> s >> t;
		for (int i = 1; i <= m; i++) {
			scanf("%d%d%lf%lf", &e[i].u, &e[i].v, &e[i].t, &e[i].d);
			add(e[i].u, e[i].v, e[i].t, e[i].d);
			add(e[i].v, e[i].u, e[i].t, e[i].d);
		}
		sort(e + 1, e + m + 1, cmp);
		for (int i = 1; i <= n; i++) fa[i] = i;
		int rec = 0;
		ans_t = 0;
		for (int i = 1; i <= m; i++) {
			int x = get(e[i].u), y = get(e[i].v);
			int ok1 = 0, ok2 = 0;
			if (get(s) != get(t)) ok1 = 1;
			if (x != y) {
				fa[x] = y;
				if (get(s) == get(t)) ok2 = 1;
				if (ok1 && ok2) ans_t = e[i].t;
				if (++rec == n - 1) break;
			}
		}
		ans_d = 1e9;
		dfs(s, 0);
		int sz = (int) ans.size();
		for (int i = 0; i < sz; i++) {
			cout << ans[i] << (i < sz - 1 ? ' ' : '\n');
		}
		printf("%.1f %.1f\n", ans_d, ans_t);
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值