题意:给出n个点编号从0到n-1和m条边,要求求出从0到n-1的所有最短路中经过的边权之和的两倍
定理:对于一条边,如果起点到该边的其中一个端点的最短距离加上终点到另外一个端点的最短距离加上该边的边权等于起点到终点的最短距离,则该边为最短路径上的一条边
思路:用dijkstra算法分别求出起点到其它点的最短距离和终点到其他点的最短距离,然后遍历每一条边,如果该边满足定理,则将该边的边权加入结果
代码:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define INF 0x3f3f3f3f
#define pb push_back
#define int long long
#define Mirai ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
using namespace std;
const int N=3e6+10;
typedef pair<int,int> PII;
vector<PII> g[N];
int n,m;
int d1[N],d2[N];
bool vis[N];
struct edge
{
int u,v,w;
}ed[N];
void dij(int s,int *dist)
{
priority_queue<PII,vector<PII>,greater<PII>> q;
dist[s]=0;
q.push({dist[s],s});
while(q.size())
{
auto u=q.top().second;
q.pop();
if(vis[u])continue;
vis[u]=true;
for(auto [v,w]:g[u])
{
if(dist[v]>dist[u]+w)
{
dist[v]=dist[u]+w;
q.push({dist[v],v});
}
}
}
}
void solve()
{
cin>>n>>m;
for(int i=0;i<n;i++)d1[i]=d2[i]=INF;
for(int i=0;i<m;i++)
{
int u,v,w;
cin>>u>>v>>w;
ed[i]={u,v,w};
g[u].pb({v,w});
g[v].pb({u,w});
}
int ans=0;
dij(0,d1);
for(int i=0;i<n;i++)vis[i]=false;
dij(n-1,d2);
for(int i=0;i<m;i++)
{
if(d1[ed[i].u]+d2[ed[i].v]+ed[i].w==d1[n-1]||d1[ed[i].v]+d2[ed[i].u]+ed[i].w==d1[n-1])
ans+=ed[i].w*2;
}
cout<<ans<<endl;
}
signed main()
{
Mirai;
int T=1;
//cin>>T;
while(T--)
{
solve();
}
return 0;
}