关于“使用算法”的一点小思考 (洛谷P1608 路径统计 - 最短路计数

本文探讨了最短路径计数问题的解决方法,通过改进SPFA算法实现路径计数,同时介绍如何利用BFS和Kruskal思想解决特定场景下的最短路径问题。

最短路计数这个问题,我一开始想的是,先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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值