题目链接
思路:一开始还想着用tarjan求桥去了。。。其实做法就是判断一下u->v这条边是不是最短路上的边就行了,怎么判断呢从1为起点和以n为起点跑两遍spfa,看看d1【u】+d2【v】+wd1【v】,由于是无向边别忘了反向判断也就是d2【u】+d1【v】+wd2【1】,这样就能判断这条边是不是最短路上的边了,至于怎么判断去掉这条边能不能走遍所有点呢?我用的是再跑一遍spfa,只要没有点的d==inf就可以了,或者用并查集也可以,码风比较丑,思路懂就行。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e5+1;
const ll inf=1e18;
int cnt,tot,u[maxn],v[maxn],w[maxn],ans[maxn];
bool vis[maxn];
ll d1[maxn],d2[maxn],d3[maxn];
struct node{
int v,w,id;
};
vector<node>g[maxn],e[maxn],p[maxn];
void spfa1(int x)
{
memset(vis,false,sizeof(vis));
for(int i=0;i<maxn;++i) d1[i]=inf;
d1[x]=0;
queue<int>q;
q.push(x);
vis[x]=true;
while(!q.empty())
{
int top=q.front();
q.pop();
vis[top]=false;
for(auto v:g[top])
{
if(d1[top]+v.w<d1[v.v])
{
d1[v.v]=d1[top]+v.w;
if(!vis[v.v]) q.push(v.v),vis[v.v]=true;
}
}
}
}
void spfa2(int x)
{
memset(vis,false,sizeof(vis));
for(int i=0;i<maxn;++i) d2[i]=inf;
d2[x]=0;
queue<int>q;
q.push(x);
vis[x]=true;
while(!q.empty())
{
int top=q.front();
q.pop();
vis[top]=false;
for(auto v:e[top])
{
if(d2[top]+v.w<d2[v.v])
{
d2[v.v]=d2[top]+v.w;
if(!vis[v.v]) q.push(v.v),vis[v.v]=true;
}
}
}
}
void spfa3(int x)
{
memset(vis,false,sizeof(vis));
for(int i=0;i<maxn;++i) d3[i]=inf;
d3[x]=0;
queue<int>q;
q.push(x);
vis[x]=true;
while(!q.empty())
{
int top=q.front();
q.pop();
vis[top]=false;
for(auto v:p[top])
{
if(d3[top]+v.w<d3[v.v])
{
d3[v.v]=d3[top]+v.w;
if(!vis[v.v]) q.push(v.v),vis[v.v]=true;
}
}
}
}
int main()
{
int n,m;
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d %d %d",&u[i],&v[i],&w[i]);
g[u[i]].push_back({v[i],w[i],i});
g[v[i]].push_back({u[i],w[i],i});
e[u[i]].push_back({v[i],w[i],i});
e[v[i]].push_back({u[i],w[i],i});
}
spfa1(1);spfa2(n);
for(int i=1;i<=m;++i)
{
if(d1[u[i]]+d2[v[i]]+w[i]==d1[n]||d2[u[i]]+d1[v[i]]+w[i]==d2[1]) continue;
p[u[i]].push_back({v[i],w[i],i});
p[v[i]].push_back({u[i],w[i],i});
}
spfa3(1);
for(int i=1;i<=n;++i)
if(d3[i]==inf){
cout<<"NO"<<endl;return 0;
}
cout<<"YES"<<endl;
}