Loading

白兰花

一道最短路。

给定一个 n 个点 m 条边的无向图 G,求 G 上 1 到其他点的最短路的长度。

当然,只要求最短路未免过于简单,假设一条路径上的边权依次为 w1,w2,,wk,于是定义 S(w)=minwimaxwi+wi 为路径长度,他希望你能帮他求出在这个定义下的最短路。

如果不联通,请输出 1000000000000000000

考场思路

max,min 都不是很好处理,因此考虑给他换一个形式,发现可以转换为最大的这条边的边权变成最小的这条边的边权,还是不好做

考虑转换为一条边的边权可以变成 0,另一条边的边权变成两倍,这样最短路一定会是由 min,max 组成的,分层图即可。

不知道怎么处理可能先变 0 或者先变两倍,所以我场上跑了两次 dijkstra 一次钦定先变 0,一次钦定先变 2 倍。

code

#include <bits/stdc++.h>
#define rep(i, j, k) for(int i = (j); i <= (k); i ++)
#define per(i, j, k) for(int i = (j); i >= (k); i --)
#define all(x) x.begin(), x.end()
#define sz(x) (int)x.size()
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<LL, int> PLI;
const int N = 6e5 + 5, M = 2e6 + 5, INF = 0x3f3f3f3f;
const LL mod = 1e9 + 7;
int n, m;
int h[N], to[M << 1], val[M << 1], nxt[M << 1], cnt;
void add(int u, int v, int w) {
	to[++ cnt] = v, val[cnt] = w, nxt[cnt] = h[u], h[u] = cnt;
}
struct Node {
	int u, v, w;
} edge[M];
LL dist[N], ans[N];
bool st[N];
/*
一条边边权变成0,一条边边权变成2倍

先变0还是先变2倍。。。不会
跑两边取min试试( 

三层?
u->v w
u'->v' w
u'' -> v'' w
u->v' 0
u' -> v'' 2*w
*/
void dijkstra() {
	rep(i, 1, n * 3) dist[i] = 1e18, st[i] = false;
	priority_queue<PLI, vector<PLI>, greater<PLI> > q;
	q.push({0, 1});
	dist[1] = 0;
	while(q.size()) {
		int u = q.top().se;
		q.pop();
		if(st[u]) continue;
		st[u] = true;
		for(int i = h[u]; i; i = nxt[i]) {
			int v = to[i], w = val[i];
			if(dist[v] > dist[u] + w) {
				dist[v] = dist[u] + w;
				q.push({dist[v], v});
			}
		}
	}
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); cout.tie(nullptr);
	cin >> n >> m;
	rep(i, 1, m) { // 第一遍钦定先变0在变2倍 
		int u, v, w;
		cin >> u >> v >> w;
		edge[i] = {u, v, w};
		add(u, v, w), add(v, u, w);
		add(u + n, v + n, w), add(v + n, u + n, w);
		add(u + n * 2, v + n * 2, w), add(v + n * 2, u + n * 2, w);
		add(u, v + n, 0), add(v, u + n, 0); 
		add(u + n, v + n * 2, w * 2), add(v + n, u + 2 * n, w * 2);
	}
	dijkstra();
	rep(i, 1, n) ans[i] = min(dist[i], dist[i + n * 2]);
	cnt = 0;
	memset(h, 0, sizeof h);
	rep(i, 1, m) {
		int u = edge[i].u, v = edge[i].v, w = edge[i].w;
		add(u, v, w), add(v, u, w);
		add(u + n, v + n, w), add(v + n, u + n, w);
		add(u + n * 2, v + n * 2, w), add(v + n * 2, u + n * 2, w);
		add(u, v + n, w * 2), add(v, u + n, w * 2);
		add(u + n, v + n * 2, 0), add(v + n, u + n * 2, 0);
	}
	dijkstra();
	rep(i, 1, n) ans[i] = min(ans[i], dist[i + n * 2]);
	rep(i, 2, n) cout << ans[i] << ' ';
    return 0;
}

贴个官方解法,比我的好处理。

min,max 不好处理,考虑把他看成路径上有一条边要支付
两次代价,一条边可以免费,然后要最小化权值。
这样一条路径想要权值最小,一定会 +min,max,并且也
不能更小。
因此考虑建立分层图,dis(u,0/1,0/1) 表示从 1 走到 u,是
否会有一条边支付了两次,是否有一条边免费了。
时间复杂度 O(nlogn)

posted @   Svemit  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示