最短路计数这个问题,我一开始想的是,先SPFA求最短路d,然后暴力找所有路径,加上最优性剪枝,看等于d的路径有几条。。。但是考虑到我已经写了SPFA了,并且一个算法并不一定只能解决一个问题,把这个SPFA改一改可能会更好一点,于是考虑对SPFA进行修改,因为SPFA实质上就是不断松弛路径,所以可以同时维护一个数组dis,表示到点的最短路路径条数,这样就会好很多
所以在使用算法上,不一定要把算法考虑成黑箱,而应该把函数考虑成黑箱
算法本身的性质,或者某部分过程,都可以拿来为我所用,这就叫运用所学知识,借鉴所学算法
再举个例子,边权为1的图上的多源最短路怎么求?(图上的点到一个点集的最短路)
可以搞多源BFS,把几个源头在开始同时入队,由BFS的性质可知,边权为1的图,一个点第一次被访问就是最短路了
还有走廊泼水节那道题,也是借鉴了kruskal的思想,对边进行排序
路径统计:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 100000 + 10;
const int MOD = 1000000000 + 7;
int n,ee,ans[MAXN],dis[MAXN],edge_tot,vis[MAXN],gra[2010][2010],last[MAXN];
struct st {
int id,dis;
bool operator < (const st &a) const {
return dis > a.dis;
}
};
struct Edge{
int u,v,w,to;
Edge(){}
Edge(int u, int v, int w, int to) : u(u), v(v), w(w), to(to) {}
}e[4000010];
inline void add(int u, int v, int w) {
e[++edge_tot] = Edge(u,v,w,last[u]);
last[u] = edge_tot;
}
priority_queue<st> q;
void dij() {
memset(dis, 0x3f, sizeof(dis));
dis[1] = 0;
ans[1] = 1;
q.push((st){1, 0});
while(!q.empty()) {
st now = q.top();
q.pop();
int x = now.id;
if(vis[x]) continue;
vis[x] = 1;
for(int i=last[x]; i; i=e[i].to) {
int v = e[i].v, w = e[i].w;
if(dis[v] > dis[x] + w) {
dis[v] = dis[x] + w;
ans[v] = ans[x];
q.push((st){v, dis[v]});
} else if(dis[v] == dis[x] + w) {
ans[v] += ans[x];
}
}
}
}
int main() {
scanf("%d %d", &n, &ee);
memset(gra, 0x3f, sizeof(gra));
int temp_check = gra[1][1];
for(int i=1; i<=ee; i++) {
int u,v,w;
scanf("%d %d %d", &u, &v, &w);
gra[u][v] = min(gra[u][v], w);
}
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
if(gra[i][j] != temp_check) {
add(i, j, gra[i][j]);
}
}
}
dij();
if(dis[n] != temp_check) printf("%d %d\n", dis[n], ans[n]);
else printf("No answer\n");
return 0;
}