20260622 - 最短路 总结



老师老师你给我们放 2300 是认真的吗啊啊啊啊啊。
最短路好难啊。
A - 邮递员送信
Tag:最短路,Dijkstra。
发现要求的就是从 \(1\) 到每个点的最短路之和,以及从每个点到 \(1\) 的最短路之和,的和。至于为什么 \(1\) 到 \(u\) 的最短路与 \(u\) 到 \(1\) 的最短路不同呢,因为题目给的是单向边。
写个 Dijkstra 模版就行了。
时间复杂度:\(O(n^2 \log n)\)。
戳这里看代码
#include<bits/stdc++.h>
#define LL long long
#define UInt unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
#define _i128 __int128
using namespace std;
const int N= 1005;
struct node{int u,val;};
bool operator < (const node &A , const node &B){
return A.val>B.val;
}
int n,m,dis[N],Ans;
vector<pii> g[N];
priority_queue<node> q;
int read(){
int su=0,pp=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
return su*pp;
}
void Dijkstra(int st){
while(!q.empty())q.pop();
memset(dis,0x3f,sizeof(dis));
dis[st]=0,q.push({st,0});
while(!q.empty()){
auto [u,ds]=q.top();q.pop();
for(auto [v,w]:g[u])
if(dis[v]>ds+w)dis[v]=ds+w,q.push({v,dis[v]});
}
}
int main(){
n=read(),m=read();
for(int i=1;i<=m;i++){
int x=read(),y=read(),z=read();
g[x].pb({y,z});
}
Dijkstra(1);
for(int i=1;i<=n;i++)Ans+=dis[i];
for(int i=1;i<=n;i++)
Dijkstra(i),Ans+=dis[1];
cout<<Ans<<"\n";
return 0;
}
B - Dijkstra?
Tag:最短路,Dijkstra,路径记录。
罚时原因:
- 没有判
-1。- 给 Dijkstra 加了个 \(vis\) 数组,但还是没判
-1。- 不知道加了啥,但还是没判
-1。
发现就是让你跑一个普通的最短路然后记录路径并输出即可,那不是随便写个 Dijkstra 就结束了吗。
时间复杂度:\(O(n \log n)\)。
戳这里看代码
#include<bits/stdc++.h>
#define LL long long
#define UInt unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
#define _i128 __int128
using namespace std;
const int N = 1e5+5;
const LL INF = 0x3f3f3f3f3f3f3f3f;
struct node{LL u,val;};
bool operator < (const node &A , const node &B){
return A.val>B.val;
}
LL n,m,dis[N],Ans,lst[N];
bool vis[N];
stack<int> stk;
vector<pii> g[N];
priority_queue<node> q;
LL read(){
LL su=0,pp=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
return su*pp;
}
void Dijkstra(int st){
while(!q.empty())q.pop();
memset(dis,0x3f,sizeof(dis));
dis[st]=0,q.push({st,0});
while(!q.empty()){
auto [u,ds]=q.top();q.pop();
if(vis[u])continue;
vis[u]=1;
for(auto [v,w]:g[u])
if(dis[v]>ds+w)
dis[v]=ds+w,q.push({v,dis[v]}),lst[v]=u;
}
}
int main(){
n=read(),m=read();
for(int i=1;i<=m;i++){
int x=read(),y=read(),z=read();
g[x].pb({y,z}),g[y].pb({x,z});
}
Dijkstra(1);
if(dis[n]>=INF){cout<<"-1\n";return 0;}
int now=n;
while(now!=1)
stk.push(now),now=lst[now];
cout<<"1 ";
while(!stk.empty()){cout<<stk.top()<<" ";stk.pop();}
cout<<"\n";
return 0;
}
C - Train
Tag:最短路,Dijkstra。
罚时原因:
- 没给
priority_queue的结构体类型开long long。- 给 Dijkstra 加了个 \(vis\) 数组,但还是没开
long long。
发现加了这个开车时间,不会要按照取模后的结果来分层记录吧?事实上到达时间最短的一定是最优的,这个太一眼了,很好证。只是处理边代价的时候不止路程时间,还要加上一个等车(换乘)时间,这个随便算一下就行了。因此本质还是一个 Dijkstra。
时间复杂度:\(O(n \log n)\)。
戳这里看代码
#include<bits/stdc++.h>
#define LL long long
#define UInt unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
#define _i128 __int128
using namespace std;
const int N = 1e5+5;
const LL INF = 0x3f3f3f3f3f3f3f3f;
struct node{LL u,val;};
bool operator < (const node &A , const node &B){
return A.val>B.val;
}
struct lines{LL to,tim,wei;};
LL n,m,X,Y,dis[N];
bool vis[N];
vector<lines> g[N];
priority_queue<node> q;
LL read(){
LL su=0,pp=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
return su*pp;
}
LL Dist(int u,int v,LL k,LL t,LL lst){
return (lst+k-1)/k*k+t;
}
void Dijkstra(){
while(!q.empty())q.pop();
memset(dis,0x3f,sizeof(dis));
dis[X]=0,q.push({X,0});
while(!q.empty()){
auto [u,ds]=q.top();q.pop();
if(vis[u])continue;vis[u]=1;
for(auto [v,k,t]:g[u])if(!vis[v]){
LL nxt=Dist(u,v,k,t,ds);
if(dis[v]>nxt)dis[v]=nxt,q.push({v,dis[v]});
}
}return;
}
int main(){
n=read(),m=read(),X=read(),Y=read();
for(int i=1;i<=m;i++){
LL x=read(),y=read(),t=read(),k=read();
g[x].pb({y,k,t}),g[y].pb({x,k,t});
}Dijkstra();
if(dis[Y]>=INF)cout<<"-1\n";
else cout<<dis[Y]<<"\n";
return 0;
}
D - 灾后重建
Tag:最短路,Floyd。
发现 \(n\) 值很小可以 Floyd,而用 Dijkstra 每次去更新一个点是麻烦且不好做的,直接上板子 Floyd。反正题目也保证了询问时间不降,那也不需要离线,每次按顺序加好足够的点(直接 Floyd \(O(n^2)\) 更新即可)然后直接查询对应的 \(dis_{x,y}\) 即可。
记得判断一下查询的 \(x\) 和 \(y\) 是否都已经恢复了,如果有一个还在施工那么答案是 \(-1\)。
时间复杂度:\(O(n^3 + Q)\)。
戳这里看代码
#include<bits/stdc++.h>
#define LL long long
#define UInt unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
#define _i128 __int128
using namespace std;
const int N = 205;
const int INF = 0x3f3f3f3f;
int n,m,t[N],Q,now,dis[N][N];
bool vis[N];
vector<pii> g[N];
int read(){
int su=0,pp=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
return su*pp;
}
void change(int k){
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
return;
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++)t[i]=read();
memset(dis,0x3f,sizeof(dis));
for(int i=1;i<=n;i++)dis[i][i]=0;
for(int i=1;i<=m;i++){
int x=read()+1,y=read()+1,z=read();
g[x].pb({y,z}),g[y].pb({x,z});
dis[x][y]=min(dis[x][y],z),dis[y][x]=min(dis[y][x],z);
}
Q=read(),now=0;
while(Q--){
int x=read()+1,y=read()+1,tim=read();
while(now<n&&t[now+1]<=tim)change(++now);
int res=-1;
if(t[x]<=tim&&t[y]<=tim&&dis[x][y]<INF)res=dis[x][y];
cout<<res<<"\n";
}
return 0;
}
E - Wormholes G
Tag:最短路,判负环,SPFA,Floyd。
罚时原因:
- 误以为起点只能是 \(1\),事实上起点可以是任何节点。
吃了不会 SPFA 的亏啊啊啊一直没做。直到快结束了想起来好像 Floyd 也能做,于是赶在老师控屏之前交了,但是由于洛谷被人卡评测了(大概是的)导致评测了十万个世纪才出来结果。
首先我们发现这个题目,啊,不就是想让我们判负环吗!然后写个 SPFA 板子就行了,但是,我已经把 SPFA 忘到十霄云外了,怎么办呢。
哦!我们发现 \(n\) 只有 \(500\) 可以三方,那 Floyd 不就出场了!Floyd 也能处理负权,于是我们跑个 \(O(n^3)\) 的 Floyd,然后最后判断是否存在 \(dis_{x,x} < 0\) 就行了 /oh。
时间复杂度:\(O(n^3)\)。
戳这里看代码
#include<bits/stdc++.h>
#define LL long long
#define UInt unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
#define _i128 __int128
using namespace std;
const int N = 505;
const int INF = 0x3f3f3f3f;
int T,n,m,k;
int dis[N][N];
int read(){
int su=0,pp=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
return su*pp;
}
int main(){
T=read();
while(T--){
n=read(),m=read(),k=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)dis[i][j]=INF;
for(int i=1;i<=n;i++)dis[i][i]=0;
for(int i=1;i<=m;i++){
int x=read(),y=read(),w=read();
dis[x][y]=min(dis[x][y],w),dis[y][x]=min(dis[y][x],w);
}
for(int i=1;i<=k;i++){
int x=read(),y=read(),w=read();
dis[x][y]=min(dis[x][y],-w);
}
for(int k=1;k<=n;k++)for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
int ans=1;
for(int i=1;i<=n;i++)ans=min(ans,dis[i][i]);
if(ans<0)cout<<"YES\n";
else cout<<"NO\n";
}
return 0;
}
F - Greg and Graph
Tag:最短路,Floyd。
删点是不可做的,但倒过来变成加点就可做了。人话:离线。
发现加点方便的就是 Floyd,而 \(n\) 是 \(500\) 也支持三方,于是套个 Floyd 板子就行了,和 D 其实挺类似的。
时间复杂度:\(O(n^3)\)。
戳这里看代码
#include<bits/stdc++.h>
#define LL long long
#define UInt unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
#define _i128 __int128
using namespace std;
const int N = 505;
LL n,a[N][N],d[N],dis[N][N],ans[N];
bool vis[N];
LL read(){
LL su=0,pp=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
return su*pp;
}
void change(int k){
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
return;
}
int main(){
n=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)dis[i][j]=read();
for(int i=1;i<=n;i++)d[i]=read();
for(int i=n;i>=1;i--){
vis[d[i]]=1;change(d[i]);
for(int x=1;x<=n;x++)if(vis[x])
for(int y=1;y<=n;y++)if(vis[y])ans[i]+=dis[x][y];
}for(int i=1;i<=n;i++)
cout<<ans[i]<<" ";cout<<"\n";
return 0;
}
G - 飞行路线
Tag:最短路,Dijkstra,分层图。
发现普通的 Dijkstra 倒闭了,因为这里需要考虑免费乘坐的次数。但是 \(k \le 10\) 实在小,考虑经典 trick 分层图,分成 \(k+1\) 层分别表示免费乘坐 \(0 \sim k\) 次的答案。然后按分层后的形式跑 Dijkstra,正确性就是有保障的了。
时间复杂度:\(O(nk \log {nk})\)。
戳这里看代码
#include<bits/stdc++.h>
#define LL long long
#define UInt unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
#define _i128 __int128
using namespace std;
const int N = 1e5+4;
const int INF = 0x3f3f3f3f;
struct node{int u,k,val;};
bool operator < (const node &A , const node &B){
return A.val>B.val;
}
int n,m,k,S,T,dis[N][12],Ans;
vector<pii> g[N];
priority_queue<node> q;
int read(){
int su=0,pp=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
return su*pp;
}
void Dijkstra(int st){
while(!q.empty())q.pop();
memset(dis,0x3f,sizeof(dis));
dis[S][0]=0,q.push({S,0,0});
while(!q.empty()){
auto [u,i,ds]=q.top();q.pop();
for(auto [v,w]:g[u]){
if(dis[v][i]>ds+w)dis[v][i]=ds+w,q.push({v,i,dis[v][i]});
if(i<k&&dis[v][i+1]>ds)dis[v][i+1]=ds,q.push({v,i+1,dis[v][i+1]});
}
}
}
int main(){
n=read(),m=read(),k=read();
S=read()+1,T=read()+1;
for(int i=1;i<=m;i++){
int x=read()+1,y=read()+1,z=read();
g[x].pb({y,z}),g[y].pb({x,z});
}Dijkstra(S);Ans=INF;
for(int i=0;i<=k;i++)Ans=min(Ans,dis[T][i]);
cout<<Ans<<"\n";
return 0;
}
H - Shortest Path
Tag:最短路,Dijkstra,二分查找 / STL。
重点在于发现这个 \(n\) 只有 \(3000\) 支持 \(O(n^2)\),而判定是否存在连续的三个点只需在维护 \(dis\) 数组时额外加上“上一步”这个维度。这是可以做到的,然后你再把违规的连续三点 Hash 一下存进数组里排序,每一步走的时候二分查找一下不违规即可。
如果不想写二分也可以塞进一个 map 或 set 里然后去查找。
时间复杂度:\(O(n^2 \log n^2 \log k)\)。
戳这里看代码
#include<bits/stdc++.h>
#define LL long long
#define UInt unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
#define _i128 __int128
using namespace std;
const int N = 3005;
const int K = 1e5+5;
const int INF = 0x3f3f3f3f;
struct node{LL x,ls,val;};
bool operator < (const node &A , const node &B){
return A.val>B.val;
}
LL n,m,k,no[K],dis[N][N];
pii lst[N][N];
LL Ans,shg,now;
bool vis[N][N];
vector<int> g[N];
priority_queue<node> q;
stack<int> rod;
int read(){
int su=0,pp=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
return su*pp;
}
LL node(LL x,int y,int z){
return x*100000000ll+y*10000+z;
}
void Dijkstra(){
while(!q.empty())q.pop();
memset(dis,0x3f,sizeof(dis));
dis[1][0]=0,q.push({1,0});
while(!q.empty()){
auto [u,ls,ds]=q.top();q.pop();
if(vis[u][ls])continue;
vis[u][ls]=1;
for(int v:g[u]){
LL id=lower_bound(no+1,no+k+1,node(ls,u,v))-no;
if(id<=k&&no[id]==node(ls,u,v))continue;//犯法
if(vis[v][u])continue;
if(dis[v][u]>ds+1){
dis[v][u]=ds+1,q.push({v,u,ds+1});
lst[v][u]={(int)(u),(int)(ls)};
}
}
}
}
int main(){
n=read(),m=read(),k=read();
for(int i=1;i<=m;i++){
int x=read(),y=read();
g[x].pb(y),g[y].pb(x);
}
for(int i=1;i<=k;i++){
int x=read(),y=read(),z=read();
no[i]=node(x,y,z);
}
sort(no+1,no+k+1);
memset(dis,0x3f,sizeof(dis));
Dijkstra();
now=0;
for(int i=1;i<=n;i++)
if(dis[n][i]<dis[n][now])now=i;
if(dis[n][now]>=INF){cout<<"-1\n";return 0;}
cout<<dis[n][now]<<"\n";
shg=n;rod.push(shg);
while(shg!=1){
rod.push(now);
int tmp=now;
now=lst[shg][now].se,shg=tmp;
}
while(!rod.empty()){
cout<<rod.top()<<" ";
rod.pop();
}
cout<<"\n";
return 0;
}
I - Buy a Ticket
Tag:最短路,Dijkstra,虚点。
罚时原因:
- Dijkstra 没写 \(vis\) 数组导致队列 MLE 了。
想不到虚点一切都倒闭,想得到虚点一切都结束。就两个字。
大概就是你发现这个 \(a_i\) 只和去到的最终城市有关而与起点无关,考虑建一个超级源点也就是虚点 \(n+1\),向每个 \(i\) 连一条权值为 \(a_i\) 的边。建模成功了,此时只要从这个虚点 \(n+1\) 出发跑 Dijkstra,得到的每个 \(dis_i\) 就是答案了。
别问我为什么,问就是想到虚点一切好说。
时间复杂度:\(O(n \log n)\)。
戳这里看代码
#include<bits/stdc++.h>
#define LL long long
#define UInt unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
#define _i128 __int128
using namespace std;
const int N = 2e5+5;
struct node{LL u,val;};
bool operator < (const node &A , const node &B){
return A.val>B.val;
}
LL n,m,a[N],dis[N],Ans;
bool vis[N];
vector<pLL> g[N];
priority_queue<node> q;
LL read(){
LL su=0,pp=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
return su*pp;
}
void Dijkstra(int st){
while(!q.empty())q.pop();
memset(dis,0x3f,sizeof(dis));
dis[st]=0,q.push({st,0});
while(!q.empty()){
auto [u,ds]=q.top();q.pop();
if(vis[u])continue;vis[u]=1;
for(auto [v,w]:g[u])
if(!vis[v]&&dis[v]>ds+w)dis[v]=ds+w,q.push({v,dis[v]});
}
}
int main(){
n=read(),m=read();
for(int i=1;i<=m;i++){
LL x=read(),y=read(),z=read();
g[x].pb({y,2*z}),g[y].pb({x,2*z});
}
for(int i=1;i<=n;i++)
a[i]=read(),g[n+1].pb({i,a[i]});
Dijkstra(n+1);
for(int i=1;i<=n;i++)
cout<<dis[i]<<" ";cout<<"\n";
return 0;
}
J - Complete The Graph
Tag:最短路,Dijkstra,极值思想,构造。
罚时原因:
- 没考虑最开始赋值 \(\inf\) 答案恰好 \(=L\) 的情况。
- 把 \(n\) 和 \(m\) 的大小都开成 \(1000\) 了,令人感到奇怪的是居然不报 RE 而是 TLE,诡异。
极值思想运用的很好,很好的一道题,但是 2300,原地吓哭。
首先考虑将所有未定义边权赋值为 \(\inf\)(可以直接不建)跑一次 Dijkstra。如果这种情况下答案 \(>L\) 说明还需要通过未定义边权来调整;如果答案 \(=L\) 则直接输出即可;如果答案 \(<L\) 原地无解,因为加新边不可能让最短路变长。
接着我们枚举每一条新边,将其边权赋值为 \(1\) 加入图中,然后再跑一次 Dijkstra。如果此时答案 \(>L\) 说明还需要继续调整,那么保留这条边,进入下一条;否则答案 \(\le L\),可以输出了,但是如果当前答案 \(< L\) 则还需要调整使边权恰好为 \(L\)。怎么调整呢?由于加入这条新边后导致从 \(>L\) 变为了 \(\le L\),说明路径一定经过了这条边,那么把这条新边的边权当做 \(L-Dis+1\) 即可。不难证明这样一定是对的。
时间复杂度:\(O(n^2 \log n)\)。
戳这里看代码
#include<bits/stdc++.h>
#define LL long long
#define UInt unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
#define _i128 __int128
using namespace std;
const int N = 1e5+5;
const int INF = 0x3f3f3f3f;
const int MAX = 1e9+7;
struct node{LL x,val;};
bool operator < (const node &A , const node &B){
return A.val>B.val;
}
struct lines{LL x,y,w;}ln[N];
LL n,m,L,S,T,no[N],ncnt,bel[N];
LL dis[N];bool vis[N];
priority_queue<node> q;
vector<pLL> g[N];
int read(){
int su=0,pp=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
return su*pp;
}
void Dijkstra(int St){
while(!q.empty())q.pop();
for(int i=0;i<n;i++)dis[i]=INF,vis[i]=0;
dis[St]=0,q.push({St,0});
while(!q.empty()){
auto [u,ds]=q.top();q.pop();
if(vis[u])continue;vis[u]=1;
for(auto [v,w]:g[u])
if(!vis[v]&&dis[v]>ds+w)
dis[v]=ds+w,q.push({v,dis[v]});
}return;
}
void print_Ans(int pos){
cout<<"YES\n";
for(int i=1;i<=m;i++)
if(ln[i].w)cout<<ln[i].x<<" "<<ln[i].y<<" "<<ln[i].w<<"\n";
else if(bel[i]<pos)cout<<ln[i].x<<" "<<ln[i].y<<" 1\n";
else if(bel[i]>pos)cout<<ln[i].x<<" "<<ln[i].y<<" "<<MAX<<"\n";
else cout<<ln[i].x<<" "<<ln[i].y<<" "<<L-dis[T]+1<<"\n";
}
int main(){
n=read(),m=read();
L=read(),S=read(),T=read();
for(int i=1;i<=m;i++){
int x=read(),y=read(),z=read();
ln[i]={x,y,z};
if(!z){no[++ncnt]=i,bel[i]=ncnt;continue;}
g[x].pb({y,z}),g[y].pb({x,z});
}Dijkstra(S);
if(dis[T]<L){cout<<"NO\n";return 0;}
if(dis[T]==L){print_Ans(0);return 0;}
for(int i=1;i<=ncnt;i++){
auto [x,y,z]=ln[no[i]];
g[x].pb({y,1}),g[y].pb({x,1});
Dijkstra(S);
if(dis[T]>L)continue;
print_Ans(i);return 0;
}cout<<"NO\n";
return 0;
}
总结
最短路是个坏东西,后面忘了。
最短路好像就是 Dijkstra / SPFA / Floyd / BFS / 01BFS 吧,还有啥,还有啥我也不会了,不过我也不会 SPFA 啊。哦哦还有一个常用 trick(?算吗)就是分层图 /oh。
Thanks reading.

浙公网安备 33010602011771号