【2018/11/05測試T2】規避
阿新 • • 發佈:2019-02-15
【題目】
【分析】
比較妙的一道題
其實直接統計不相遇的情況是比較困難的,以正難則反的思想,我們不如直接統計出總數和相遇的情況,一減就是答案
首先,跑最短路(跑兩遍,從 開始跑一遍,記在 中,從 開始跑一遍,記在 中),並統計出最短路數量(假設為 ),那總方案數就是 (小 B 有 種走法,小 Z 也有 中)
然後呢,由於速度相同,他們相遇的位置一定是在路徑的中點(就是邊權總和除以 的位置)
那麼,現在就分情況討論:
- 他們在一個點相遇,條件是 ,那麼這種走法的方案數就是 , 就是最短路數量
- 他們在邊上的一點相遇(假設為 ),條件是 且 ,方案數為
因此我們列舉點和邊,以上面的兩種操作統計合法方案,做完之後減一下就是答案了
【程式碼】
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define M 500005
#define Mod 1000000007
using namespace std;
int n,m,s,t,tot;
int d[2][N],num[2][N];
int first[N],v[M],w[M],nxt[M];
bool vis[ N];
priority_queue<pair<int,int> >q;
void add(int x,int y,int z)
{
tot++;
nxt[tot]=first[x];
first[x]=tot;
v[tot]=y;
w[tot]=z;
}
void dijkstra(int s,int k)
{
int x,y,i;
num[k][s]=1;
memset(vis,false,sizeof(vis));
memset(d[k],127/3,sizeof(d[k]));
q.push(make_pair(0,s));d[k][s]=0;
while(!q.empty())
{
x=q.top().second;q.pop();
if(vis[x])continue;vis[x]=true;
for(i=first[x];i;i=nxt[i])
{
y=v[i];
if(d[k][y]>d[k][x]+w[i])
{
num[k][y]=num[k][x];
d[k][y]=d[k][x]+w[i];
q.push(make_pair(-d[k][y],y));
}
else if(d[k][y]==d[k][x]+w[i])
num[k][y]=(num[k][x]+num[k][y])%Mod;
}
}
}
int main()
{
// freopen("access.in","r",stdin);
// freopen("access.out","w",stdout);
int x,y,z,i,j;
scanf("%d%d",&n,&m);
scanf("%d%d",&s,&t);
for(i=1;i<=m;++i)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z),add(y,x,z);
}
dijkstra(s,0);
dijkstra(t,1);
long long sum=1ll*num[0][t]*num[0][t]%Mod;
for(i=1;i<=n;++i)
{
if(d[0][i]+d[1][i]!=d[0][t]) continue;
if(d[0][i]==d[1][i])
sum=(sum-1ll*num[0][i]*num[0][i]%Mod*num[1][i]%Mod*num[1][i]%Mod+Mod)%Mod;
for(j=first[i];j;j=nxt[j])
{
int to=v[j];
if(d[0][i]+w[j]+d[1][to]!=d[0][t]) continue;
if(d[0][to]>d[1][to]&&d[0][i]<d[1][i])
sum=(sum-1ll*num[0][i]*num[0][i]%Mod*num[1][to]%Mod*num[1][to]%Mod+Mod)%Mod;
}
}
printf("%lld",sum);
// fclose(stdin);
// fclose(stdout);
return 0;
}