版权声明:欢迎转载 https://blog.csdn.net/suntengnb/article/details/80026671
问题描述:
给出一个N个顶点M条边的无向无权图,顶点编号为1~N。问从顶点1开始,到其他每个点的最短路有几条。
AC代码:
typedef pair<int,int> Pair;//到源点的距离、顶点编号
priority_queue<Pair,vector<Pair>,greater<Pair> > pq;//小顶堆
struct edge
{
int to;
int next;
int w;
};
edge e[2000010];
int head[1000010];
int id = 1;
int n,m;
int dis[1000010];//距离
int cnt[1000010];//cnt[i]表示从源点到顶点i的最短路的条数
void add_edge(int u,int v,int w)
{
e[id].to = v;
e[id].next = head[u];
e[id].w = w;
head[u] = id;
id++;
}
void dijkstra(int s)//堆优化
{
memset(dis,0x3F,sizeof(dis));//初始化
dis[s] = 0;//初始化
cnt[1] = 1;//递推边界
pq.push(make_pair(dis[s],s));//将源点入堆
while(!pq.empty())
{
int v = pq.top().second;
pq.pop();
for(int i = head[v]; i != -1; i = e[i].next)
{
int to = e[i].to;
int w = e[i].w;
if(dis[to] == dis[v] + w)//如果和当前的最短路长度相等
cnt[to] = (cnt[to] + cnt[v]) % Mod;//则加上cnt[中转点v]
if(dis[to] > dis[v] + w)//如果比当前的最短路还要短
{
dis[to] = dis[v] + w;//更新
cnt[to] = 0;//置0
cnt[to] = (cnt[to] + cnt[v]) % Mod;//加上cnt[中转点v]
pq.push(make_pair(dis[to],to));//因为dis[to]被松弛了,再入堆
}
}
}
return;
}
int main()
{
cin >> n >> m;
memset(head,-1,sizeof(head));//初始化
for(int i = 1; i <= m; ++i)
{
int a,b;
scanf("%d%d",&a,&b);
if(a == b)//去掉自环
continue;
add_edge(a,b,1);
add_edge(b,a,1);
}
dijkstra(1);
for(int i = 1; i <= n; ++i)
cout << cnt[i] << endl;
return 0;
}
解决方法:
因为路径的长度都是1,考虑用邻接矩阵的幂次去做,逐次累乘,判断是否可达,答案为第一次可达时的
再就是考虑用最短路算法,比如Dijkstra去做(为了跑得快一点,加了堆优化),然后在用中转点松弛这一步上做文章,被松弛了说明要推翻之前的最短路条数,恰好相等则要加上,就这样递推。对于每一个中转点来说,它到源点的路径长度已经是最短的了,不会再被松弛,最短路的条数也确定了。