调出一堆 (sb) 错误的题,例如:"YES" 写成“Yes”将近半下午没了 = =
给你一张 (n) 个点,(m) 条边的图,每条边有一个正整数权值。有些边的边权未知。你需要给每条权值未知的边确定一个不超过 (10^{18}) 的正整数权值,使得 (S) 到 (T) 的最短路恰好为 (L) 。
无解输出 (−1)
(2 ≤ n ≤ 1000,1 ≤ m ≤ 2000,1 ≤ L ≤ 10^9,S ≠ T)
solution
首先把未知的边的权值都赋为最小的正整数 (1), 然后跑一遍最短路,如果最短路的长度大于 (L) 那么最短路肯定不会是 (L)
如果最短路的恰好等于 (L) 直接输出答案就好了
对于如果大于 (L) ?
一开始是这么想的:跑一遍最短路,然后找出最短路上的可以变化权值的边(一开始为 0 的边)增大权值,直到这条最短路恰好为 L,然后继续跑最短路,判断是否还存在 < L 的最短路,重复这个操作,直到找不到为止,这样到最后肯定存在一条长度为 (L) 的最短路
发现这样会跑很多次最短路,就没写 (其实是我不会写)
题解的思路
跑两次最短路,第一次的记为 (dis[i][0]) 第二次的记为 (dis[i][1])
先跑完第一次最短路,求出 (need = L - dis[T][0]) 也就是距目标还差多少
跑第二次最短路的时候,如果到达一个点的最短路可以更新,并且 (dis[u] + e[i].w < dis[v] + need) 就把 (e[i].w) 更新为 (dis[v] + need - dis[u])
这样走到 (v) 点就相当于最短路加上了 (need) 妙哉 = =
code
/*
work by:Ariel_
mind: 把未知的边都设为 1,跑一遍最短路,如果最短路大于 L,则一定无解
如果此时 = L, 此时就是答案
如果此时小于 L,就调整这条路径上的边,使得它成为 L,然后再跑最短路,重复此操作
直到最后找不到小于 L 的路径
判断一条边是否为最短路上的边:两边 dij,
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#define int long long
#define rg register
using namespace std;
const int M = 1e5 + 5, N = 1e5 + 5;
const int INF = 0x3f3f3f3f3f3f;
typedef pair<int, int> PII;
int read(){
int x = 0,f = 1; char c = getchar();
while(c < '0'||c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') {x = x*10 + c - '0'; c = getchar();}
return x*f;
}
int n, m, L, S, T, opt[N], need;
struct edge{int u, v, nxt, w, fag;}e[M];
int head[N], E = 1;
void add_edge(int u, int v, int w, int fag) {
e[++E] = (edge) {u, v, head[u], w + fag, fag};
head[u] = E;
}
priority_queue<PII, vector<PII>, greater<PII> > q;
int dis[N][2], vis[N];
void dij(int k) {
memset(vis, 0, sizeof vis);
for (int i = 0; i < n; i++) dis[i][k] = INF;
dis[S][k] = 0, q.push(make_pair(0, S));
while(!q.empty()) {
int u = q.top().second; q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].v;
if (k == 1) {
if (k && e[i].fag && dis[u][1] + e[i].w < dis[v][0] + need)
e[i].w = e[i ^ 1].w = dis[v][0] + need - dis[u][1];
}
if (dis[v][k] > dis[u][k] + e[i].w) {
dis[v][k] = dis[u][k] + e[i].w;
q.push(make_pair(dis[v][k], v));
}
}
}
}
signed main(){
n = read(), m = read(), L = read(), S = read(), T = read();
for (int i = 1, u, v, w; i <= m; i++) {
u = read(), v = read(), w = read();
add_edge(u, v, w, !w), add_edge(v, u, w, !w);
}
dij(0);
if (dis[T][0] > L) {
puts("NO"); return 0;
}
need = L - dis[T][0];
dij(1);
if (dis[T][1] != L) puts("NO");
else {
puts("YES");
for (int i = 2; i <= E; i += 2) printf("%lld %lld %lld
", e[i].u, e[i].v, e[i].w);
}
return 0;
}