P1144 最短路计数
提交29.99k
通过13.03k
时间限制1.00s
内存限制125.00MB
题目描述
给出一个N个顶点M条边的无向无权图,顶点编号为1−N。问从顶点1开始,到其他每个点的最短路有几条。
输入格式
第一行包含22个正整数N,M,为图的顶点数与边数。
接下来M行,每行2个正整数x,y,表示有一条顶点x连向顶点y的边,请注意可能有自环与重边。
输出格式
共NN行,每行一个非负整数,第ii行输出从顶点1到顶点i有多少条不同的最短路,由于答案有可能会很大,你只需要输出an*smod100003后的结果即可。如果无法到达顶点i则输出0。
输入输出样例
输入 #1复制
5 7 1 2 1 3 2 4 3 4 2 3 4 5 4 5
输出 #1复制
1 1 1 2 4
说明/提示
1到5的最短路有4条,分别为2条1−2−4−5和2条1−3−4−5(由于4−5的边有2条)。
对于20%的数据,N≤100;
对于60%的数据,N≤1000;
对于100%的数据,N<=1000000,M<=2000000。
思路:可以理解成最短路,边的权重都为1,到达某点的距离最短。那么如何计算距离最短的路径有多少条呢?我们可以整一个num数组存放当前结点的路径条数,如果到达下一个点的路径更新了,那么到下一个点的路径条数应该为当前结点的路径条数,如果下一个结点的路径与他原来的距离相等,则加上去当前结点的路径。
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 1e6 + 100;
const int MAX = 1e8;
const int mod = 100003;
struct node{
int to;
int next;
int weight;
}edge[2 * maxn];
int head[maxn];
int dist[maxn];
int num[maxn];
bool vis[maxn];
int cnt = 0;
int n, m;
void init()
{
for(int i = 1; i <= n; i++){
head[i] = -1;
vis[i] = false;
dist[i] = MAX;
num[i] = 0;
}
}
void add(int u, int v)
{
edge[cnt].to = v;
edge[cnt].weight = 1;
edge[cnt].next = head[u];
head[u] = cnt++;
}
struct base{
int point, dist;
bool operator < (const base&others)const{
return dist > others.dist;
}
};
void dijkstra(int s)
{
priority_queue<base>q;
dist[s] = 0;
num[s] = 1;//源点的路径条数为1
q.push((base){s, 0});
while(!q.empty()){
base cur = q.top();
q.pop();
int u = cur.point;
if(vis[u])continue;
vis[u] = true;
for(int i = head[u]; ~i; i = edge[i].next){
int v = edge[i].to;
int w = edge[i].weight;
if(!vis[v] && dist[u] + w <= dist[v]){
if(dist[u] + w < dist[v]){//dist小,则更新路径条数
num[v] = num[u];
dist[v] = dist[u] + w;
q.push((base){v, dist[v]});//这里错了
}else{//相等,则加上路径条数
num[v] += num[u];
}
num[v] %= mod;
}
}
}
}
int main()
{
scanf("%d%d", &n, &m);
init();
while(m--){
int u, v;
scanf("%d%d", &u, &v);
add(u, v);
add(v, u);
}
dijkstra(1);
for(int i = 1; i <= n; i++){
printf("%d\n", num[i] % mod);
}
return 0;
}