思路当天没想出来,结果晚上回去的路上,突然就想到了多次找最短路,补全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; } } }