最短路
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'; // 输出从起点到该节点的路径数量或其他信息
}
}