最短路

P1144 最短路计数

\(spfa\)

#include<bits/stdc++.h> 
using namespace std;
#define int long long 
#define endl '\n'
#define ye puts("YES") 
#define no puts("NO")
#define haha puts("")  
const int N = 2e6 + 100; 
const int M = 1010; 
const int mod = 100003;

int n, m; // 定义两个全局变量n和m,分别表示图中节点的数量和边的数量
vector<int> g[N]; // 定义一个邻接表g,用于存储图的结构
int dis[N]; // 定义一个数组dis,用于存储从起点到每个节点的最短距离
bool st[N]; // 定义一个布尔数组st,用于标记节点是否在队列中
int ans[N]; // 定义一个数组ans,用于存储从起点到每个节点的某种特定信息(如路径数量)

void spfa()
{
	queue<int> q; // 定义一个队列q,用于存储待处理的节点
	int i; // 定义一个循环变量i
	for (i = 1; i <= n; i++) // 初始化dis数组为无穷大
		dis[i] = 1e18;
	q.push(1); // 将起点加入队列
	dis[1] = 0; // 起点的距离为0
	st[1] = 1; // 标记起点在队列中
	ans[1] = 1; // 从起点到起点的路径数量为1
	while (q.size()) // 当队列不为空时
	{
		auto t = q.front(); // 取出队列中的第一个节点
		q.pop(); // 将该节点从队列中移除
		st[t] = 0; // 标记该节点不在队列中
		for (auto i : g[t]) // 遍历该节点的所有邻居
		{
			int v = i; // 获取邻居节点的编号
			if (dis[v] > dis[t] + 1) // 如果通过当前节点可以到达邻居节点的更短路径
			{
				dis[v] = dis[t] + 1; // 更新邻居节点的最短距离
				ans[v] = ans[t]; // 更新从起点到邻居节点的路径数量(或其他信息)
				if (!st[v]) // 如果邻居节点不在队列中
					q.push(v); // 将邻居节点加入队列
			}
			else if (dis[v] == dis[t] + 1) // 如果通过当前节点不能到达更短的路径,但路径长度相同
			{
				ans[v] += ans[t]; // 将当前节点的路径数量加到邻居节点的路径数量上
				ans[v] %= mod; // 取模运算,防止路径数量过大
			}
		}
	}
}

signed main()
{
	cin >> n >> m; // 输入节点数量和边数量
	int i; 
	for (i = 1; i <= m; i++) // 对于每条边
	{
		int a, b; // 定义两个变量a和b,用于存储边的两个端点
		cin >> a >> b; // 输入边的两个端点
		g[a].push_back(b); // 在邻接表中添加一条从a到b的边
		g[b].push_back(a); // 因为是无向图,所以也要添加一条从b到a的边
	}
	spfa(); // 调用spfa函数计算最短路径和其他信息
	for (i = 1; i <= n; i++) // 对于每个节点
		cout << ans[i] << '\n'; // 输出从起点到该节点的路径数量(或其他信息)
}

\(dijkstra\)

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define ye puts("YES")
#define no puts("NO")
#define haha puts("")
const int N = 2e6 + 100;
const int M = 1010;
const int mod = 100003;
int n, m; // n表示节点的数量,m表示边的数量
vector<int> g[N]; // 邻接表g,用于存储图的结构
bool st[N]; // 标记数组st,用于记录节点是否已经被处理过
int dis[N]; // dis数组,用于存储从起点到每个节点的最短距离
int ans[N]; // ans数组,用于存储从起点到每个节点的某种特定信息(如路径数量)

void dijkstra()
{
	priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
	// 定义最小堆q,用于存储待处理的节点
	int i;
	for (i = 1; i <= n; i++) // 初始化dis数组为无穷大
		dis[i] = 1e18;
	dis[1] = 0; // 起点的距离为0
	ans[1] = 1; // 从起点到起点的路径数量为1
	q.push({0, 1}); // 将起点加入最小堆
	while (q.size()) // 当最小堆不为空时
	{
		auto u = q.top().second; // 取出堆顶元素,即当前最短距离的节点
		q.pop(); // 弹出堆顶元素
		if (st[u]) // 如果节点u已经被处理过,则跳过
		{
			continue;
		}
		st[u] = true; // 标记节点u为已处理
		for (auto v : g[u]) // 遍历节点u的所有邻居节点
		{
			if (dis[v] > dis[u] + 1) // 如果通过u到v的距离比当前v的最短距离更短
			{
				ans[v] = ans[u]; // 更新从起点到v的路径数量
				dis[v] = dis[u] + 1; // 更新v的最短距离
				q.push({-dis[v], v}); // 将v加入最小堆,距离取负数以实现最小堆效果
			}
			else if (dis[v] == dis[u] + 1) // 如果通过u到v的距离与v的最短距离相同
			{
				ans[v] += ans[u]; // 将从起点通过u到v的路径数量加到ans[v]上
				ans[v] %= mod; // 取模运算,防止ans[v]过大
			}
		}
	}
}

signed main()
{
	cin >> n >> m;
	int i;
	for (i = 1; i <= m; i++) // 对于每条边
	{
		int a, b; // 定义两个变量a和b,用于存储边的两个端点
		cin >> a >> b; // 输入边的两个端点
		g[a].push_back(b); // 在邻接表g中添加一条从a到b的边
		g[b].push_back(a); // 因为是无向图,所以也要添加一条从b到a的边
	}
	dijkstra(); // 调用Dijkstra算法函数
	for (i = 1; i <= n; i++) // 对于每个节点
	{
		cout << ans[i] << '\n'; // 输出从起点到该节点的路径数量或其他信息
	}
}
posted @ 2024-07-05 17:43  ZhangDT  阅读(2)  评论(0编辑  收藏  举报