思路当天没想出来,结果晚上回去的路上,突然就想到了多次找最短路,补全L后,修改其他边为1e18。直到找到最短路为L为止。 用这个思路,代码一遍就过了。终于A掉了,美滋滋!!
代码:(因本人代码水平有限,写的挺长,代码用时:2000ms)
#include <iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
#include<map>
#include<algorithm>
#define inf 0x3f3f3f3f
#include <algorithm>
#define N 10005
#define LL long long
#define mem(a,b) memset(a,b,sizeof(a));
using namespace std;
LL ansu[N],ansv[N];
LL answ[N];//存边的信息
struct node
{
LL u,v,nex,id;
LL w,flag;
} e[400500];
LL head[N],f[N],vis[N];
LL cnt,S,T,n,m;
LL dis[N],L;
void add(LL u,LL v,LL w,LL id)
{
e[cnt].id=id;//哪条边
e[cnt].u=u;
e[cnt].v=v;
e[cnt].w=w;
if(w==0) e[cnt].flag=0;//标记,边长为0,标记为0
else e[cnt].flag=1;
e[cnt].nex=head[u];
head[u]=cnt++;
}
void init()
{
mem(head,-1);
cnt=0;
}
queue<LL>q;
map<LL,LL>ma;
void spfa(LL flag)
{
mem(f,-1);
mem(vis,0);
memset(dis,0x3f,sizeof dis);//初始化
dis[S]=0LL;//dis[i]表示i到出发点S的最短距离
vis[S]=1;//标记是否已经加入队列
while(!q.empty())
q.pop();
q.push(S);
while(!q.empty())
{
LL u=q.front();
q.pop();
for(LL i=head[u]; ~i; i=e[i].nex)
{
LL v=e[i].v;
LL w=e[i].w;
if(flag&&!w) continue;//flag为1的话,算最短路不带边长为0的边
if(dis[v]<=dis[u]+w) continue;
dis[v]=dis[u]+w;//更新v到S的最短距离
if(!flag) f[v]=i;//更新dis[v]后,更新f[v],f[v]存u到v的这条路的编号i,通过这个来找到最短路路径。
if(vis[v]) continue;
vis[v]=1;
q.push(v);
}
vis[u]=0;
}
}
int main()
{
init();
scanf("%lld%lld%lld%lld%lld",&n,&m,&L,&S,&T);
for(LL i=0; i<m; i++)
{
scanf("%lld%lld%lld",&ansu[i],&ansv[i],&answ[i]);
add(ansu[i],ansv[i],answ[i],i);
add(ansv[i],ansu[i],answ[i],i);
}
spfa(1);
if(dis[T]<L)//计算出最短路(不带0的边),若太小,改变边长为0的边,也无法改变这条最短路的值。
{
printf("NO\n");
return 0;
}
else if(dis[T]==L)//找到答案
{
printf("YES\n");
for(LL i=0; i<m; i++)
printf("%lld %lld %lld\n",ansu[i],ansv[i],answ[i]==0LL?L+10:answ[i]);
return 0;
}
for(int i=0;i<cnt;i++)//让所有的边长为0的边变成1(正整数)中的最小值
if(!e[i].flag)
answ[e[i].id]=e[i].w=1;
while(1)
{
spfa(0);//求出最短路
if(dis[T]>L)
{
printf("NO\n");//第一次求出此值,这是整个图的最短路,因为边长为零的边一定至少是1,第一次就没有大于L,那么以后也不可能再大于L。
return 0;
}
else if(dis[T]==L)
{
printf("YES\n");
for(LL i=0; i<m; i++)
printf("%lld %lld %lld\n",ansu[i],ansv[i],answ[i]);
return 0;
}
else
{
LL u=T;
ma.clear();
LL sum=L-dis[T];
while(u!=S)
{
if(!e[f[u]].flag)
{
answ[e[f[u]].id]=e[f[u]].w=e[f[u]].w+sum;//将sum(差值)添加到第一个可修改边上。
sum=0;
ma[e[f[u]].id]=1;//标记此最短路上可修改的边的id
}
u=e[f[u]].u;//f[u]为找到上一个节点的编号。
}
for(int i=0;i<cnt;i++)//此条最短路以外的所有可修改的边全部修改成1e18,
if(!e[i].flag&&!ma[e[i].id])
answ[e[i].id]=e[i].w=L+10;
}
}
}