最短路之--Floyd

博客介绍了Floyd算法,其复杂度为O(n^3),节点数少于300时适用,可求最短路和判断图连通性。还分享了做题对Floyd遍历方式的新理解,通过“灾后重建”“牛收费”两道题目,分析了Floyd算法在不同场景的应用及注意点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • Floyd:稳定的O(n^3)复杂度,一般只在节点数 < 300 时候考虑。除了求最短路,还可以用来判断图的连通性。

基本结构很简单:最外层遍历中转节点,内层遍历两端点,具体为什么可参见我的另一条博客。最近做题遇到了几道用Floyd的题目,又有了新的理解:设uv为两端点,k为中转节点,那么Floyd的遍历方式其实就是先只允许以1号节点进行中转,接着允许以1和2号节点进行中转,再然后允许以1、2、3号节点进行中转……最后允许1-n号节点进行中转,求最短路。每次在枚举k时,得到的是目前经过前k个节点的最短路径。

题目:灾后重建

这道题典型的floyd解法,但是光靠模板是过不了滴。一开始我用的是dijkstra,超时了,后来发现节点数不多才采用floyd。题目已经说明访问的t是非递减的,那么就无需对节点进行排序,只需要每次遍历到未超时的中转节点即可,下一次遍历直接接着上一次的节点继续往后遍历即可。

//数据量不大-->floyd。
//每当看到节点数<300时都可以考虑floyd
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define ll long long 
#define Inf 0x3f3f3f3f
const int maxv = 200 + 2;
int pt[maxv], n, m, a, b, c;
ll table[maxv][maxv];
int Q, x, y, t, k;

bool floyd(const int& st, const int& en, const int& tt){
    if(pt[st] > tt || pt[en] > tt) return false;
    while(pt[k] <= tt && k < n){
        for(int u=0; u<n; ++u){
            for(int v=0; v<n; ++v){
                if(u == v || u ==k || v == k) continue;
                // if(pt[u] > tt || pt[v] > tt) continue;//想想为什么这句不要?
                table[u][v] = min(table[u][v], table[u][k] + table[k][v]);
            }
        }
        k += 1;
    }
    return table[st][en] != Inf;
}

inline int read(){
    char ch = getchar();
    int ans = 0, tool = 1;
    while(ch < '0' || ch > '9') ch = getchar();
    while(ch >= '0' && ch <= '9'){
        ans = (ans << 3) + (ans << 1) + ch - '0';
        ch = getchar();
    }return (ans * tool);
}
int main()
{
    n = read(), m = read();
    for(int i=0; i<n; ++i)    //table只需要初始化一次,因为之后的t都是增加的
        for(int j=0; j<n; ++j)
            table[i][j] = Inf;
    for(int i=0; i<n; ++i)
        pt[i] = read();
    while(m--){
        a = read(), b = read(), c = read();
        table[a][b] = table[b][a] = c;
    }
    Q = read();
    while(Q--){
        x = read(), y = read(), t = read();
        if(floyd(x, y, t)){
            printf("%lld\n", table[x][y]);
        }
        else puts("-1");
    }
    return 0;
}
View Code

 再放一个要对k节点进行排序的,之前也放过。题目:牛收费

这道题要先将节点权值较小的先遍历,越大的越后遍历,为何这样我现在有些似懂非懂,不敢乱说,先放这给我几天再想想,若有高人能给我指点更好不过。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define Inf 0x3f3f3f3f
#define ll long long
const int maxn = 250 + 4;
struct Node{
    int w, id;
}node[maxn];
ll table[maxn][maxn], dis[maxn][maxn];
int n, m, k, u, v, w, st, en;
int newid[maxn];
inline int read(){
    char ch = getchar();
    int ans = 0;
    while(ch < '0' || ch > '9') ch = getchar();
    while(ch >= '0' && ch <= '9'){
        ans = (ans << 3) + (ans << 1) + ch - '0';
        ch =getchar();
    }return ans;
}
inline bool comp(const Node& a, const Node& b){
    return a.w < b.w;
}

inline void floyd(){
    for(int k=1; k<=n; ++k){
        for(int i=1; i<=n; ++i){
            for(int j=1; j<=n; ++j){
                if(i == j || i == k || j == k) continue;
                table[i][j] = min(table[i][j], table[i][k] + table[k][j]);
                dis[i][j] = min(dis[i][j], table[i][j] + max(node[k].w, max(node[i].w, node[j].w)));
            }
        }
    }
    return;
}
//涉及到最短路和最短路上的最大节点,用两个数组分别存储
//由于floyd中间节点由前往后遍历,所以我们把权值越大的点越往后遍历
//使得最终遍历到k==n时,保证如果选取中间节点选取的节点是所有中间节点中权值最大的
int main()
{
    memset(table, Inf, sizeof(table));
    memset(dis, Inf, sizeof(dis));
    n = read(), m = read(), k = read();
    for(int i=1; i<=n; ++i) 
        {node[i].w = read(), node[i].id = i, table[i][i] = 0;}
    sort(node+1, node+n+1, comp); //节点按权值升序
    for(int i=1; i<=n; ++i)
        newid[node[i].id] = i; 
        //相当于把我想要优先遍历的序号排在前边
        //这样在floyd中的遍历就更加方便注意之后的存图位置也要用newid数组

    for(int i=1; i<=m; ++i){
        u = read(), v = read(), w = read();
        table[newid[u]][newid[v]] = table[newid[v]][newid[u]] = min(table[newid[u]][newid[v]], (ll)w);
        //为方便之后的floyd访问,用newid【】数组来获取新的顺序编号
        //转换之后,权值较小的节点会被优先遍历到
        //注意可能会有重边,所以要有一个min()判断一下
    }

    floyd();
    while(k--){
        st = read(), en = read();
        printf("%lld\n", dis[newid[st]][newid[en]]);
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/GorgeousBankarian/p/11158839.html

内容概要:该研究通过在黑龙江省某示范村进行24小时实地测试,比较了燃煤炉具与自动/手动进料生物质炉具的污染物排放特征。结果显示,生物质炉具相比燃煤炉具显著降低了PM2.5、CO和SO2的排放(自动进料分别降低41.2%、54.3%、40.0%;手动进料降低35.3%、22.1%、20.0%),但NOx排放未降低甚至有所增加。研究还发现,经济性和便利性是影响生物质炉具推广的重要因素。该研究不仅提供了实际排放数据支持,还通过Python代码详细复现了排放特征比较、减排效果计算和结果可视化,进一步探讨了燃料性质、动态排放特征、碳平衡计算以及政策建议。 适合人群:从事环境科学研究的学者、政府环保部门工作人员、能源政策制定者、关注农村能源转型的社会人士。 使用场景及目标:①评估生物质炉具在农村地区的推广潜力;②为政策制定者提供科学依据,优化补贴政策;③帮助研究人员深入了解生物质炉具的排放特征和技术改进方向;④为企业研发更高效的生物质炉具提供参考。 其他说明:该研究通过大量数据分析和模拟,揭示了生物质炉具在实际应用中的优点和挑战,特别是NOx排放增加的问题。研究还提出了多项具体的技术改进方向和政策建议,如优化进料方式、提高热效率、建设本地颗粒厂等,为生物质炉具的广泛推广提供了可行路径。此外,研究还开发了一个智能政策建议生成系统,可以根据不同地区的特征定制化生成政策建议,为农村能源转型提供了有力支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值