题目大意
给出一个有
N
(
2
<
=
N
<
=
1000
)
N(2<=N<=1000)
N(2<=N<=1000)个顶点
M
(
N
−
1
<
=
M
<
=
N
∗
(
N
−
1
)
/
2
)
M(N-1<=M<=N*(N-1)/2)
M(N−1<=M<=N∗(N−1)/2)条边的无向连通图。设
d
i
s
t
1
[
i
]
dist1[i]
dist1[i]表示在这个无向连通图中,顶点
i
i
i到顶点
1
1
1的最短距离。
现在要求你在这个图中删除
M
−
(
N
−
1
)
M-(N-1)
M−(N−1)条边,使得这个图变成一棵树。设
d
i
s
t
2
[
i
]
dist2[i]
dist2[i]表示在这棵树中,顶点
i
i
i到顶点
1
1
1的距离。
你的任务是求出有多少种删除方案,使得对于任意的
i
i
i,满足
d
i
s
t
1
[
i
]
=
d
i
s
t
2
[
i
]
dist1[i]=dist2[i]
dist1[i]=dist2[i]。
题目解析
如果点
1
1
1到点
i
i
i的最短路大于点
j
j
j,且
i
i
i到
j
j
j的路径有可能出现在最短路上(即
d
i
s
[
i
]
=
d
i
s
[
j
]
+
l
e
n
[
i
]
[
j
]
dis[i]=dis[j]+len[i][j]
dis[i]=dis[j]+len[i][j]),那
i
i
i点的方案数
+
1
+1
+1。
最后把所有点的方案数乘起来就是答案,注意开
l
o
n
g
long
long
l
o
n
g
long
long。
也就是求点
1
1
1到其他点的最路径条数相乘。
代码
#include<bits/stdc++.h>
using namespace std;
int n,m;
int dis[1005],t[1005];
queue<int> q;
bool vis[1005];
int ls[1005],cnt;
struct edge{int v,w,next;}e[1000005];
void ins(int x,int y,int w){e[++cnt].v=y;e[cnt].w=w;e[cnt].next=ls[x];ls[x]=cnt;}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1,u,v,w;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
ins(u,v,w);ins(v,u,w);
}
memset(dis,0x3f,sizeof(dis));
dis[1]=0;q.push(1);int x,y;
while(!q.empty())
{
x=q.front();q.pop();vis[x]=0;
for(int i=ls[x];i;i=e[i].next)
{
y=e[i].v;
if(dis[x]+e[i].w<dis[y])
{
dis[y]=dis[x]+e[i].w;
t[y]=1;
if(!vis[y])
{
vis[y]=1;
q.push(y);
}
}
else if(dis[x]+e[i].w==dis[y])
t[y]++;
}
}
long long ans=1;
for(int i=2;i<=n;i++) (ans*=t[i])%=2147483647;
cout<<ans%2147483647;
}