最短路计数

题目描述

给出一个N个顶点M条边的无向无权图,顶点编号为1−N。问从顶点1开始,到其他每个点的最短路有几条。

输入格式

第一行包含2个正整数N,M,为图的顶点数与边数。

接下来M行,每行2个正整数x,y,表示有一条顶点x连向顶点y的边,请注意可能有自环与重边

输出格式

共N行,每行一个非负整数,第i行输出从顶点1到顶点i有多少条不同的最短路,由于答案有可能会很大,你只需要输出ans mod 100003后的结果即可。如果无法到达顶点i则输出0

用到的知识点

1、广度优先搜索

2、vector容器

开成一个vector数组,其实也可以用邻接表即链表的形式来储存数据

3、存储顶点深度的数组

dep[maxm]

4、存储顶点是否访问过的数组

vis[maxm]

5、储存最短路径条数的数组

cnt[maxn]:值得品味

6、循环条件为队列不为0

7、思考

可以使用一个类来表示顶点,类中的数据成员为顶点标识、顶点深度、是否被访问过;
再使用一个链表数组来代替vector类,具体操作方式与vector类相似;
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
using namespace std;
//广度优先搜素默认就是最短路径搜索

const int maxn = 1000000 + 1, maxm = 2000000 + 1, INF = 0x7f7f7f7f, MOD = 100003;
vector<int>G[maxn];             //这是一个vector数组
int dep[maxn]; 
bool vis[maxn];                 //其中的数据都置为0
int cnt[maxn];

int main() {
	int N, M; scanf("%d%d", &N, &M);
	for (int i = 1; i <= M; i++) {
		int x, y; scanf("%d%d", &x, &y);
		G[x].push_back(y);     //第x个顶点与第y个顶点相连(在这里面可以存放多个顶点)
		G[y].push_back(x);     //第y个顶点与第x个顶点相连
	}
	queue<int>Q;               //创建队列
	dep[1] = 0; 
	vis[1] = 1; 
	Q.push(1); 
	cnt[1] = 1;
	while (!Q.empty()) {      //判断队列是否为空
		int x = Q.front();    //取出队列中最前面的元素
		Q.pop();              //删除最前面的元素
		for (int i = 0; i < G[x].size(); i++) {
			int t = G[x][i];                //取出其中的一个顶点
			if (!vis[t]) {                  //对于访问过的顶点不再操作
				vis[t] = 1;                 
				dep[t] = dep[x] + 1;        //取出顶点的深度等于原来顶点深度+1 
				Q.push(t);                  //将该顶点挤入队列中等待被读取
			}
			if (dep[t] == dep[x] + 1) { 
				cnt[t] = (cnt[t] + cnt[x]) % MOD;            //这里要算的是条数(cnt【i】保存的是到i顶点的最短路径数)
			}
		}
	}
	for (int i = 1; i <= N; i++) {
		printf("%d\n", cnt[i]);
	}
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值