来源:JZOJ
题目描述
给出一个 个顶点 条边的无向无权图,顶点编号为 。
问从顶点 开始,到其他每个点的最短路有几条。
解题思路
- 这是一道 最短路,只需在 的模板上稍加改动就可以 ,算是比较套路了;
- 具体怎么实现呢?我们不妨设想,
- 如果 ( 表示根节点到 的距离),是不是说明找到了第二条最短路?思考一下;
- 所以,这样我们就可以写代码了,用 表示根节点到 的最短路条数;
美妙的 时间
#include <bits/stdc++.h>
using namespace std;
int q[400005],linkk[100005],ans[100005],dis[100005],vis[100005];
int n,m,tot=0;
struct node
{
int y,next;
}e[400005];
void insert(int x,int y) //邻接表
{
e[++tot].y=y;
e[tot].next=linkk[x]; linkk[x]=tot;
}
void SPFA(int st)
{
for (int i=1;i<=n;i++) dis[i]=1e9;
memset(vis,0,sizeof(vis));
dis[st]=0; vis[st]=1;
ans[st]=1;
int head=1,tail=1;
q[1]=st;
for (head=1;head<=tail;head++)
{
int x=q[head]; //取出队头
for (int i=linkk[x];i;i=e[i].next)
{
int y=e[i].y;
if (dis[x]+1<dis[y]) //迭代
{
dis[y]=dis[x]+1; //更新
ans[y]=ans[x];
if (!vis[y])
{
q[++tail]=y; //进队
vis[y]=1; //标记
}
}
else
if (dis[x]+1==dis[y])
{
ans[y]=(ans[x]+ans[y])%100003; //累加
}
}
vis[x]=0; //出队
}
}
int main()
{
freopen("shortest.in","r",stdin);
freopen("shortest.out","w",stdout);
scanf("%d %d",&n,&m);
for (int i=1;i<=m;i++)
{
int x,y;
scanf("%d %d",&x,&y);
insert(x,y); //邻接表插入
insert(y,x);
}
SPFA(1);
for (int i=1;i<=n;i++)
{
if (dis[i]==1e9) printf("0\n"); //如果没有最短路
else printf("%d\n",ans[i]);
}
return 0;
}