最短路计数与次短路计数
最短路计数
AcWing 1134. 最短路计数
题目链接
https://www.acwing.com/problem/content/1136/
解析
- n个点m条边的无向无权图
- 通过dp递推记录最短路条数
- 需证明求最短路的过程中可以递推地计数,可以证明用dijkstra和bfs求最短路的时候点的扩展是拓扑图,可以进行递推计数
- 条件限制:(好像是不能有权值为0的环?????还是边权非负啊???待确认。。。。)
- 本题套用bfs的板子
Ac代码
点击查看代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1e5 + 10, M = 4e5 + 10, mod = 100003;
int h[N], e[M], ne[M], idx;
int n, m;
int dist[N], cnt[N];
queue<int> q;
void add(int a, int b){
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
void bfs(){
memset(dist, 0x3f, sizeof dist);
dist[1]= 0, cnt[1] = 1;
q.push(1);
while(q.size()){
auto t = q.front();
q.pop();
for(int i = h[t]; i != -1; i = ne[i]){
int j = e[i];
if(dist[j] > dist[t] + 1){
dist[j] = dist[t] + 1;
cnt[j] = cnt[t];
q.push(j);
}
else if(dist[j] == dist[t] + 1) cnt[j] = (cnt[j] + cnt[t]) % mod;
}
}
return;
}
int main()
{
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
while(m --){
int a, b;
scanf("%d%d", &a, &b);
add(a, b), add(b, a);
}
bfs();
for(int i = 1; i <= n; i ++) printf("%d\n", cnt[i]);
return 0;
}
次短路计数
AcWing 383. 观光
题目链接
https://www.acwing.com/problem/content/385/
解析
- 本题主要用了拆点和最短路计数
- 本题要同时进行最短路计数和次短路计数,均采用递推思想,可以在bfs或者dijkstra的同时完成
- 由于最短路和次短路的更新都会影响未来点的最短路和次短路的更新,所以要拆点,拆点方法就是放弃传统dijkstra在堆中维护pii的想法,在堆中存储自定义的struct并重载运算符,然后递推更新答案
- 记录和更新最短路和次短路的代码写法较为固定,可以学习
Ac代码
点击查看代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1010, M = 1e4 + 10;
struct Ver{
int id, type, d;
bool operator > (const Ver &W) const{
return d > W.d;
}
};
int n, m, S, T;
int h[N], e[M], ne[M], w[M], idx;
int dist[N][2], cnt[N][2];
bool st[N][N];
void add(int a, int b, int c){
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}
int dijkstra(){
memset(cnt, 0, sizeof cnt);
memset(st, 0, sizeof st);
memset(dist, 0x3f, sizeof dist);
dist[S][0] = 0, cnt[S][0] = 1;
priority_queue<Ver, vector<Ver>, greater<Ver>> heap;
heap.push({S, 0, 0});
while(heap.size()){
Ver t = heap.top();
heap.pop();
int ver = t.id, type = t.type, distance = t.d, count = cnt[ver][type];
if(st[ver][type]) continue;
st[ver][type] = true;
for(int i = h[ver]; i != -1; i = ne[i]){
int j = e[i];
if(dist[j][0] > distance + w[i]){
dist[j][1] = dist[j][0];
cnt[j][1] = cnt[j][0];
heap.push({j, 1, dist[j][1]});
dist[j][0] = distance + w[i];
cnt[j][0] = count;
heap.push({j, 0, dist[j][0]});
}
else if(dist[j][0] == distance + w[i]) cnt[j][0] += count;
else if(dist[j][1] > distance + w[i]){
dist[j][1] = distance + w[i];
cnt[j][1] = count;
heap.push({j, 1, dist[j][1]});
}
else if(dist[j][1] == distance + w[i]) cnt[j][1] += count;
}
}
int res = cnt[T][0];
if(dist[T][1] == dist[T][0] + 1) res += cnt[T][1];
return res;
}
int main()
{
int cases;
scanf("%d", &cases);
while(cases --){
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
while(m --){
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
}
scanf("%d%d", &S, &T);
printf("%d\n", dijkstra());
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架