题解:
题意大致为给定1e31e31e3的无向图,且给定起点sss和终点ttt,以及部分知道长度的边,让你补全不知道长度的边使得从sss到ttt的最短路为LLL
解题可以分为3个步骤
- 不将不知道长度的边跳过,求最短路,若最短路小于L则一定不可能成功输出NO,若等于则将未知边长设定为INF若大于则执行2
- 将所有未知边都设成1,跑最短路,若最短路大于L则一定不能成功(因为题意规定边长最小为1)输出NO,否则执行第3步
- 首先在第二步中回溯一遍最短路,将经过的未知边打上标记。对于未打上标记的未知边设值为INF,其他值为1,然后依次枚举这些点二分这些点的答案,跑最短路。(每次确定一点答案后再跑一遍最短路,若最短路为L则推出枚举)
代码:
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
//#include <random>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define PB push_back
#define MP make_pair
#define INF 1073741824
#define inf 1000000000000000000
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
//mt19937 rand_(time(0));
const int N=3e5+7,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//逆元
ll wei[M];
int head[N],NEXT[M],ver[M],tot;void link(int u,int v,ll w){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;wei[tot]=w;}
ll dis[N];
bool vis[N],mark[N],flag[N];
int que[N],pre[N];
int s,t;
int n;
ll L;
bool dij(int x){
for(int i=1;i<=n;i++){
dis[i]=inf;
vis[i]=false;
}
dis[x]=0;
priority_queue<pair<ll,int> >q;
q.push(MP(0,x));
while(!q.empty()){
x=q.top().second;
q.pop();
if(vis[x]) continue;
vis[x]=true;
for(int i=head[x];i;i=NEXT[i]){
int y=ver[i];
if(mark[i/2]) continue;
if(dis[y]>dis[x]+wei[i]){
dis[y]=dis[x]+wei[i];
q.push(MP(-dis[y],y));
}
}
}
if(dis[t]<L) return false;
else true;
}
bool DIJ(int x){
for(int i=1;i<=n;i++){
dis[i]=inf;
vis[i]=false;
}
dis[x]=0;
priority_queue<pair<ll,int> >q;
q.push(MP(0,x));
while(!q.empty()){
x=q.top().second;
q.pop();
if(vis[x]) continue;
vis[x]=true;
for(int i=head[x];i;i=NEXT[i]){
int y=ver[i];
//cout<<mark[i/2]<<' '<<y<<' '<<x<<endl;
if(dis[y]>dis[x]+(mark[i/2]?1LL:wei[i])){
dis[y]=dis[x]+(mark[i/2]?1LL:wei[i]);
q.push(MP(-dis[y],y));
pre[y]=i;
//cout<<y<<' '<<x<<endl;
}
}
}
// for(int i=1;i<=n;i++) cout<<dis[i]<<' ';
// cout<<endl;
//cout<<dis[t]<<endl;
if(dis[t]>L) return false;
else true;
}
void dijs(int x){
for(int i=1;i<=n;i++){
dis[i]=inf;
vis[i]=false;
}
dis[x]=0;
priority_queue<pair<ll,int> >q;
q.push(MP(0,x));
while(!q.empty()){
x=q.top().second;
q.pop();
if(vis[x]) continue;
vis[x]=true;
for(int i=head[x];i;i=NEXT[i]){
int y=ver[i];
if(dis[y]>dis[x]+wei[i]){
dis[y]=dis[x]+wei[i];
q.push(MP(-dis[y],y));
}
}
}
}
int main(){
//freopen("1.txt","r",stdin);
//ios::sync_with_stdio(false);
int m;
int u,v;
ll w;
tot=1;
scanf("%d%d%d%d%d",&n,&m,&L,&s,&t);
s++,t++;
for(int i=1;i<=m;i++){
scanf("%d%d%lld",&u,&v,&w);
link(u+1,v+1,w);
link(v+1,u+1,w);
if(w==0) mark[i]=true;
}
if(dij(s)){
if(dis[t]==L){
puts("YES");
for(int i=1;i<=m;i++){
if(mark[i])
printf("%d %d %lld\n",ver[i*2+1]-1,ver[i*2]-1,inf);
else
printf("%d %d %lld\n",ver[i*2+1]-1,ver[i*2]-1,wei[i*2]);
}
return 0;
}
if(DIJ(s)){
int tmp=t;
int ant=0;
while(tmp!=s){
if(mark[pre[tmp]/2]){
que[++ant]=pre[tmp]/2;
flag[pre[tmp]/2]=true;
}
tmp=ver[pre[tmp]^1];
}
for(int i=1;i<=m;i++){
if(mark[i]){
if(flag[i]){
wei[i*2]=wei[i*2+1]=1LL;
}
else {
wei[i*2]=wei[i*2+1]=inf;
}
}
}
for(int i=1;i<=ant;i++){
ll l=1,r=inf;
while(l<=r){
ll mi=(l+r)/2LL;
wei[que[i]*2]=wei[que[i]*2+1]=mi;
dijs(s);
if(dis[t]>L) r=mi-1;
else l=mi+1;
}
wei[que[i]*2]=wei[que[i]*2+1]=r;
dijs(s);
if(dis[t]==L) break;
}
puts("YES");
for(int i=1;i<=m;i++){
if(mark[i])
printf("%d %d %lld\n",ver[i*2+1]-1,ver[i*2]-1,wei[i*2]);
else
printf("%d %d %lld\n",ver[i*2+1]-1,ver[i*2]-1,wei[i*2]);
}
}
else puts("NO");
}
else puts("NO");
//cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
return 0;
}