题目
思路
考虑直接打通这条路!那么类似于做一个最小生成树。也就是说,每次给未知边 ⟨ u , v ⟩ \lang u,v\rang ⟨u,v⟩ 赋权值,其满足 u ∈ T , v ∉ T u\in T,v\notin T u∈T,v∈/T(这里 T T T 是已得到的 “生成树”),于是 d i s v dis_v disv 就得到了。
然后你会发现不对。因为有些边是固定的,它会导致我们所认为的 d i s dis dis 偏大。那么悬崖勒马,直接把 “未知边” 设置为 1 1 1 来修正这一情况。可是此时怎么调整出 L L L 呢?
其实我们有两步。第一步,让最短路不能小于
L
L
L 。第二步,让最短路恰好为
L
L
L 。革命必须分成两步走。
所以我们再跑一次最短路。在运行过程中,我们尽量让新的 d i s ′ dis' dis′ 变大,使其成为 d i s + f dis+f dis+f,这里 f = L − d i s t f=L-dis_t f=L−dist 即差距。让 d i s dis dis 增大是第一步的要求,让它只增大到 d i s + f dis+f dis+f 是第二步的要求。
正确性如何?考虑任意一个点的前驱,它既不会过大,也不会太小。所以我们每个点的要求都是最容易达到的。所以最终 d i s t ′ = L dis'_t=L dist′=L 是最容易达到的。
复杂度
O
(
n
log
n
)
\mathcal O(n\log n)
O(nlogn) 。都
0202
\sout{\;0202\;}
0202年了不会还有人用
s
p
f
a
\sout{\;\rm spfa\;}
spfa吧?
代码
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
inline int readint(){
int a = 0; char c = getchar(), f = 1;
for(; c<'0'||c>'9'; c=getchar())
if(c == '-') f = -f;
for(; '0'<=c&&c<='9'; c=getchar())
a = (a<<3)+(a<<1)+(c^48);
return a*f;
}
inline void writeint(int x){
if(x > 9) writeint(x/10);
putchar((x-x/10*10)^48);
}
const int MaxN = 20005;
struct Edge{
int to, nxt, val;
Edge(){ }
Edge(int T,int N,int W){
to = T, nxt = N, val = W;
}
};
Edge e[MaxN];
int head[MaxN], cntEdge;
void addEdge(int a,int b,int c){
e[cntEdge] = Edge(b,head[a],c);
head[a] = cntEdge ++;
}
int dis[MaxN], n, L;
bool vis[MaxN];
void dijkstra(int from){
for(int i=0; i<n; ++i)
dis[i] = L+1, vis[i] = 0;
dis[from] = 0;
for(int i=0,id; i<n; ++i){
for(int j=0*(id=-1); j<n; ++j){
if(vis[j]) continue;
if(!~id || dis[j] < dis[id])
id = j; // minimum
}
if(!~id || dis[id] == L+1)
return ; // nothing to do
vis[id] = true;
// printf("dis[%d] = %d\n",id,dis[id]);
if(dis[id] > L) dis[id] = L+1;
for(int i=head[id]; ~i; i=e[i].nxt){
int x = dis[id]+e[i].val;
if(!e[i].val) ++ x; // w = 1
if(dis[e[i].to] > x)
dis[e[i].to] = x;
}
}
}
int tmp[MaxN];
void bfs(int from,int f){
for(int i=0; i<n; ++i)
tmp[i] = L+1, vis[i] = 0;
tmp[from] = 0;
for(int i=0,id; i<n; ++i){
id = -1; // not used
for(int j=0; j<n; ++j){
if(vis[j]) continue;
if(!~id || tmp[j] < tmp[id])
id = j; // minimum
}
if(!~id || tmp[id] == L+1)
return ; // nothing to do
vis[id] = true;
if(tmp[id] > L) tmp[id] = L+1;
for(int i=head[id]; ~i; i=e[i].nxt){
if(e[i].val == 0){
e[i].val = dis[e[i].to];
e[i].val += f-tmp[id];
if(e[i].val < 1) // at least
e[i].val = 1;
if(e[i].val > L) // at most
e[i].val = L;
}
int x = tmp[id]+e[i].val;
if(tmp[e[i].to] > x)
tmp[e[i].to] = x;
}
}
}
int main(){
n = readint();
int m = readint();
L = readint();
int zxy = readint();
int sxy = readint();
for(int i=0; i<n; ++i)
head[i] = -1;
for(int i=0,a,b,c; i<m; ++i){
a = readint(), b = readint();
addEdge(a,b,c = readint());
addEdge(b,a,c); // undirectly
}
dijkstra(zxy), bfs(zxy,L-dis[sxy]);
if(tmp[sxy] == L){
puts("YES");
for(int i=0; i<cntEdge; i+=2){
writeint(e[i].to);
putchar(' ');
writeint(e[i^1].to);
putchar(' ');
int x = max(e[i].val,e[i^1].val);
if(!x) x = L+1; // casually
writeint(x), putchar('\n');
}
}
else puts("NO");
return 0;
}