E.旅旅旅游
题意:
给n个点m条边的带权无向图
问是否存在一种路径,能够从1开始走过所有点。
限制条件为点1到点n所有最短路径上的边不能走。
解法:
基本思路是先求出以1为起点的单源最短路,然后把1到n最短路上的边标记,
判断未被标记的边是否能够使所有点连通
判断无向图的边是否是点1到点n的最短路可以先分别求点1为起点和点n为起点的最短路
假设边为(u,v),判断min(1到u和n到v的距离,1到v和n到u的距离)+边权是否等于1到n的最短路径,如果是则标记。
判断未被标记的边是否能够使得所有点连通直接并查集判断是否能将所有点合并为一个集合即可。
ps:
spfa居然真的死了
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const signed maxm=1e6+5;
signed head[maxm],nt[maxm<<1],to[maxm<<1],w[maxm<<1],cnt;
int d[maxm],dd[maxm];
signed pre[maxm];
bool mark[maxm];
signed n,m;
int ffind(signed x){
return pre[x]==x?x:pre[x]=ffind(pre[x]);
}
void add(signed x,signed y,signed z){
cnt++;nt[cnt]=head[x];head[x]=cnt;to[cnt]=y;w[cnt]=z;
}
void dj(signed st,int *d){
for(int i=1;i<=n;i++)mark[i]=0,d[i]=1e18;
typedef pair<int,signed> PI;
priority_queue<PI,vector<PI>,greater<PI> >q;
q.push({0,st});
d[st]=0;
while(!q.empty()){
int x=q.top().second;q.pop();
mark[x]=1;
for(int i=head[x];i;i=nt[i]){
int v=to[i];
if(!mark[v]&&d[v]>d[x]+w[i]){
d[v]=d[x]+w[i];
q.push({d[v],v});
}
}
}
}
signed main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
signed a,b,c;scanf("%d%d%d",&a,&b,&c);
add(a,b,c);add(b,a,c);
}
dj(1,d);
dj(n,dd);
for(int i=1;i<=n;i++)pre[i]=i;
for(int x=1;x<=n;x++){
for(int i=head[x];i;i=nt[i]){
int v=to[i];
if(d[x]+w[i]+dd[v]!=d[n]&&d[v]+w[i]+dd[x]!=d[n]){
pre[ffind(x)]=ffind(v);
}
}
}
int sum=0;
for(int i=1;i<=n;i++){
if(pre[i]==i)sum++;
}
if(sum==1)puts("YES");
else puts("NO");
return 0;
}