题目:https://vjudge.net/contest/464115#problem/G
题意:
一个 n n n个点 m m m条边的无向图,每条边有一个边权 w w w。有一个起点 s s s和终点 t t t,求从 s s s出发到 t t t和从 t t t出发到 s s s的不相遇的两条最短路径的路径对数。
思路:
d i j k s t r a dijkstra dijkstra 求出起点到 i i i的距离 d i s [ 0 ] [ i ] dis[0][i] dis[0][i],终点到 i i i的距离 d i s [ 1 ] [ i ] dis[1][i] dis[1][i],起点到 i i i最短路的方案数 c n t [ 0 ] [ i ] cnt[0][i] cnt[0][i],终点到 i i i的最短路的方案数 c n t [ 1 ] [ i ] cnt[1][i] cnt[1][i]。
求出所有最短路径数,任选两条 C c n t [ 0 ] [ t ] 2 ∗ 2 C_{cnt[0][t]}^2*2 Ccnt[0][t]2∗2的方案数减去相遇的方案数就是答案
考虑在点上相遇
当 d i s [ 0 ] [ i ] = = d i s [ 1 ] [ i ] dis[0][i]==dis[1][i] dis[0][i]==dis[1][i]&& d i s [ 0 ] [ i ] = = 2 ∗ d i s [ 0 ] [ t ] dis[0][i]==2*dis[0][t] dis[0][i]==2∗dis[0][t]时,在点 i i i相遇的方案为 C c n t [ 0 ] [ i ] ∗ c n t [ 1 ] [ i ] 2 ∗ 2 C_{cnt[0][i]*cnt[1][i]}^2*2 Ccnt[0][i]∗cnt[1][i]2∗2
考虑在边上相遇
设边 i i i的端点 u i u_i ui, v i v_i vi, u i u_i ui理起点更近,边权为 w i w_i wi。
当 d i s [ 0 ] [ u ] + d i s [ 1 ] [ v ] + w = = d i s [ 0 ] [ t ] dis[0][u]+dis[1][v]+w==dis[0][t] dis[0][u]+dis[1][v]+w==dis[0][t]&& d i s [ 0 ] [ u ] ∗ 2 < d i s [ 0 ] [ t ] dis[0][u]*2<dis[0][t] dis[0][u]∗2<dis[0][t]&& d i s [ 1 ] [ v ] ∗ 2 < d i s [ 0 ] [ t ] dis[1][v]*2<dis[0][t] dis[1][v]∗2<dis[0][t]时,在边 i i i相遇的方案数为 C c n t [ 0 ] [ u ] ∗ c n t [ 1 ] [ v ] 2 ∗ 2 C_{cnt[0][u]*cnt[1][v]}^2*2 Ccnt[0][u]∗cnt[1][v]2∗2
代码:
#include<bits/stdc++.h>
#define MAXN 100005
#define INF 0x3f3f3f3f
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,int>P;
vector<P>G[MAXN];
const int mod=1e9+7;
struct Edge
{
int u,v,w;
}edge[MAXN*2];
ll dis[2][MAXN],cnt[2][MAXN];
int vis[MAXN];
void dijkstra(int id,int s)
{
memset(dis[id],60,sizeof(dis[id]));
memset(vis,0,sizeof(vis));
dis[id][s]=0;
cnt[id][s]=1;
priority_queue<P,vector<P>,greater<P> >q;
q.push(P(0,s));
while(!q.empty())
{
P p=q.top();q.pop();
int x=p.second;
if(vis[x])continue;
vis[x]=1;
for(P e:G[x])
{
int to=e.second;//cout<<x<<' '<<to<<' '<<dis[id][to]<<endl;
ll w=e.first;
if(dis[id][to]>dis[id][x]+w)
{
dis[id][to]=dis[id][x]+w;
cnt[id][to]=cnt[id][x];
q.push(P(dis[id][to],to));
}
else if(dis[id][to]==dis[id][x]+w)
cnt[id][to]=(cnt[id][to]+cnt[id][x])%mod;
}
}
}
int main(){
int n,m;scanf("%d%d",&n,&m);
int s,t;scanf("%d%d",&s,&t);
for(int i=1;i<=m;i++)
{
int u,v,w;scanf("%d%d%d",&u,&v,&w);
edge[i]={u,v,w};
G[u].pb(P(w,v));
G[v].pb(P(w,u));
}
dijkstra(0,s);
dijkstra(1,t);
ll ans=cnt[0][t]*(cnt[0][t]-1)%mod;//cout<<ans<<endl;
for(int i=1;i<=n;i++)
{
if(dis[0][i]==dis[1][i]&&dis[0][i]*2==dis[0][t])
{
ll tmp=cnt[0][i]*cnt[1][i]%mod;
ans=(ans-tmp*(tmp-1)%mod+mod)%mod;
}
}
for(int i=1;i<=m;i++)
{
int u=edge[i].u,v=edge[i].v,w=edge[i].w;
if(dis[0][u]>dis[0][v])swap(u,v);
if(dis[0][u]+dis[1][v]+w==dis[0][t]&&dis[0][u]*2<dis[0][t]&&dis[1][v]*2<dis[0][t])
{
ll tmp=cnt[0][u]*cnt[1][v]%mod;
ans=(ans-tmp*(tmp-1)%mod+mod)%mod;
}
}
printf("%lld\n",ans);
return 0;
}