[Daimayuan] 最短路计数(C++,DP,图论)

这篇具有很好参考价值的文章主要介绍了[Daimayuan] 最短路计数(C++,DP,图论)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

题目描述

给出一个 N N N 个顶点 M M M 条边的无向无权图。

问从顶点 1 1 1 开始,到其他每个点的最短路有几条。

输入格式

1 1 1 行包含两个正整数 N N N M M M

接下来 M M M 行,每行两个正整数 x , y x,y x,y表示存在一条由顶点 x x x 到顶点 y y y 的边。(可能存在重边和自环)

输出格式

输出 N N N 行,每行一个非负整数。

i i i 行输出从顶点 1 1 1 到顶点 i i i 的不同最短路个数。

由于数据可能很大,你只需要输出 a n s   m o d   100003 ans\ mod\ 100003 ans mod 100003 的结果。

若顶点 1 1 1 不能到达顶点 i i i,请输出 0 0 0

样例输入
5 7
1 2
1 3
2 4
3 4
2 3
4 5
4 5
样例输出
1
1
1
2
4
数据范围

1 ≤ N ≤ 1 0 6 1≤N≤10^6 1N106 1 ≤ M ≤ 2 × 1 0 6 1≤M≤2×10^6 1M2×106

提示

由于数据量较大,请使用较为快速的输入/输出方式。

解题思路

根据数据范围,我们估计算法的复杂度至多是 O ( N ) O(N) O(N),因此想到了动态规划:

对于节点 i i i,有若干个节点与之相连,在与之相连的节点当中从 1 1 1 k 1 , k 2 , . . . , k n k_1,k_2,...,k_n k1,k2,...,kn节点的路径长度相同且最短,那么我们计算得出,从 1 1 1到节点 i i i的最短路径数为 n u m [ k 1 ] + n u m [ k 2 ] + . . . + n u m [ k n ] num[k_1]+num[k_2]+...+num[k_n] num[k1]+num[k2]+...+num[kn]

以上是思路的主体部分,接下来实现代码:

数据量庞大,同时也是因为存在重边,故不能采用二维数组存图,因此采用链式前向星。

对于代码主体部分,维护一个队列与一个路径长度的数组。

初始化将 1 1 1节点加入队列,然后不断尝试到达新的节点。

void solve() {
	q.push(1);
	while (!q.empty()) {
		int node = q.front(); q.pop();
		
		for (int i = head[node]; i != -1; i = edges[i].next) {
			int v = edges[i].v;
			q.push(v);
		}
	}
}

利用队列元素先进先出的特点,我们可以保证,队首的节点永远是距离 1 1 1最近的节点。

进而我们可以保证,用队首去更新路径长度,得到的一定是最短路径长度。

void solve() {
	q.push(1);
	path[1] = 0;

	while (!q.empty()) {
		int node = q.front(); q.pop();
		int path_len = path[node] + 1;
		
		for (int i = head[node]; i != -1; i = edges[i].next) {
			int v = edges[i].v;
			if (path_len > path[v]) continue;
			if (path[v] == NaN) {//NaN代表无穷大,即为未到达的节点
				path[v] = path_len;
				q.push(v);
			}
		}
	}
}

以此为基础,很容易实现最初的思想:

void solve() {
	q.push(1);
	path[1] = 0;
	sum[1] = 1LL;

	while (!q.empty()) {
		int node = q.front(); q.pop();

		int path_len = path[node] + 1;
		
		for (int i = head[node]; i != -1; i = edges[i].next) {
			int v = edges[i].v;
			if (path_len > path[v]) continue;
			sum[v] = (sum[v] + sum[node]) % mod_num;
			if (path[v] == NaN) {
				path[v] = path_len;
				q.push(v);
			}
		}
	}
}

最后,AC代码如下:文章来源地址https://www.toymoban.com/news/detail-421576.html

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <queue>
#include <string.h>
using namespace std;
const int max_n = 1e6;
const int max_m = 2e6;
const int NaN = 0x3F3F3F3F;
const long long mod_num = 100003;

struct edge { int v, next; }edges[2 * max_m];
int tot = -1, head[max_n + 1], path[max_n + 1];
queue<int>q;
long long sum[max_n + 1];

void add_edge(int u, int v) {
	edges[++tot] = { v, head[u] }; head[u] = tot;
	edges[++tot] = { u, head[v] }; head[v] = tot;
}

void solve() {
	q.push(1);
	path[1] = 0;
	sum[1] = 1LL;

	while (!q.empty()) {
		int node = q.front(); q.pop();

		int path_len = path[node] + 1;
		
		for (int i = head[node]; i != -1; i = edges[i].next) {
			int v = edges[i].v;
			if (path_len > path[v]) continue;
			sum[v] = (sum[v] + sum[node]) % mod_num;
			if (path[v] == NaN) {
				path[v] = path_len;
				q.push(v);
			}
		}
	}
}

int main() {
	memset(head, -1, sizeof(int) * (max_n + 1));
	memset(path, 0x3F, sizeof(int) * (max_n + 1));
	int n, m;
	scanf("%d%d", &n, &m);
	//cin >> n >> m;
	int u, v;
	for (int i = 0; i < m; i++) {
		scanf("%d%d", &u, &v);
		//cin >> u >> v;
		add_edge(u, v);
	}

	solve();
	for (int i = 1; i <= n; i++) {
		printf("%lld\n", sum[i]);
	}
	return 0;
}

到了这里,关于[Daimayuan] 最短路计数(C++,DP,图论)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++ 实现】图论概念,最小生成树,单/多源最短路径实现

    首先节点的存取,V是节点key,vectorpairV,V map;其实已经能表达一个图了,但是这样保存节点对我们使用来说会导致复杂度高。 常用保存节点的方式,有矩阵和邻接表。 矩阵的优点:O(1) 时间找到两点是否相连以及他们的权值。 矩阵的缺点:找一点相邻的所有节点的时候是O(N

    2024年02月13日
    浏览(27)
  • [Daimayuan] 吃糖果(C++,贪心)

    桌子上从左到右放着 n n n 个糖果。糖果从左到右编号,第 i i i 块糖果的重量为 w i w_i w i ​ 。小明和小红要吃糖果。 小明从左边开始吃任意数量的糖果。(连续吃,不能跳过糖果) 小红从右边开始吃任意数量的糖果。(连续吃,不能跳过糖果) 当然,如果小明吃了某个糖果

    2024年02月02日
    浏览(32)
  • [Daimayuan] 添加括号(C++,数学)

    现在给出一个表达式,形如 a 1 / a 2 / a 3 / . . . / a n a_1/a_2/a_3/.../a_n a 1 ​ / a 2 ​ / a 3 ​ /.../ a n ​ 。 如果直接计算,就是一个个除过去,比如 1 / 2 / 1 / 4 = 1 / 8 1/2/1/4=1/8 1/2/1/4 = 1/8 。 然而小 A A A 看到一个分数感觉很不舒服,希望通过添加一些括号使其变成一个整数。一种可行

    2024年02月05日
    浏览(26)
  • [Daimayuan] 碰撞2(C++,模拟)

    在 x O y xOy x O y 坐标系中有 N N N 个人,第 i i i 个人的位置是 ( X i , Y i ) (X_i,Y_i) ( X i ​ , Y i ​ ) ,并且每个人的位置都不同。 我们有一个由 L 和 R 组成的长为 N N N 的字符串 S S S , S i = S_i= S i ​ = R 代表第 i i i 个人面向右, S i = S_i= S i ​ = L 代表第 i i i 个人面向左。 现在所

    2023年04月09日
    浏览(27)
  • [Daimayuan]新国王游戏(C++,数学)

    又到了 H H H 国国庆, 国王再次邀请 n n n 位大臣来玩有奖游戏。上次国庆被众臣吐槽国王小气后,国王决定今年大方点,改变游戏规则且不再参与游戏,免得被大臣们质疑。首先, 他让每位大臣在左、 右手上面分别写下一个正整数。然后让这 n n n 位大臣排成一排。排好队后,

    2023年04月08日
    浏览(26)
  • [Daimayuan] 异或和(C++,异或,数学)

    给定一个长度为 n n n 的数组 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a 1 ​ , a 2 ​ , ... , a n ​ 。 请你求出下面式子的模 1 e 9 + 7 1e9+7 1 e 9 + 7 的值。 ∑ i = 1 n − 1 ∑ j = i + 1 n ( a i   X O R   a j ) sum_{i=1}^{n-1}{sum_{j=i+1}^{n}{(a_i XOR a_j)}} ∑ i = 1 n − 1 ​ ∑ j = i + 1 n ​ ( a i ​   XOR   a j ​

    2024年02月01日
    浏览(26)
  • [Daimayuan] 三段式(C++,数组前缀和)

    有一个长度为 n n n 的序列,现在我们想把它切割成三段(每一段都是连续的),使得每一段的元素总和都相同,请问有多少种不同的切割方法 输入描述 第一行给出一个数 n n n ,( 1 ≤ n ≤ 1 0 5 1≤n≤10^5 1 ≤ n ≤ 1 0 5 ) 第二行给出序列 a 1 a_1 a 1 ​ , a 2 a_2 a 2 ​ , a 3 a_3 a 3 ​

    2024年02月05日
    浏览(27)
  • P1144 最短路计数

    给出一个 N N N 个顶点 M M M 条边的无向无权图,顶点编号为 1 ∼ N 1sim N 1 ∼ N 。问从顶点 1 1 1 开始,到其他每个点的最短路有几条。 第一行包含 2 2 2 个正整数 N , M N,M N , M ,为图的顶点数与边数。 接下来 M M M 行,每行 2 2 2 个正整数 x , y x,y x , y ,表示有一条由顶点 x x x 连

    2024年02月14日
    浏览(23)
  • P1144 最短路计数 题解

    给出一个 N N N 个顶点 M M M 条边的无向无权图,顶点编号为 1 ∼ N 1sim N 1 ∼ N 。问从顶点 1 1 1 开始,到其他每个点的最短路有几条。 第一行包含 2 2 2 个正整数 N , M N,M N , M ,为图的顶点数与边数。 接下来 M M M 行,每行 2 2 2 个正整数 x , y x,y x , y ,表示有一条由顶点 x x x 连

    2024年02月05日
    浏览(23)
  • 算法:计数类dp

      计数类动态规划(Counting DP)是一种用来解决计数问题的动态规划技术,它通常用于求解在给定条件下满足某种性质的组合或序列的总数。 计数类DP问题的特点是要求计算所有可能情况的数量,而不是求最值或是否存在这样的情况。 当然我们在使用计数类dp的时候,没必

    2024年04月15日
    浏览(15)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包