不被世界看好的SPFA依旧强势-HDU2680

记得第一次接触spfa是在高中的noip,那时候死记硬背过了pascal版本的优化之后的spfa。

当时的比赛还真用上了,因而水了个奖,毕竟学的不多,总共加起来学习pascal编程的时间不够7*24h。

看完了前情回顾,接下来就是见证奇迹的时刻,我要写spfa啦。


题目链接:HDU-2680

题目大意:一个人可以从多个起点开始出发,看到终点的最短路是多少。

题目分析:

1.如果我们把每个起点都spfa一次那么时间复杂度会加大很多。因而做个优化:设置一个0号位置,0号位置到每个起点都有一条路径,且这个路径的权重为0.这样,我们只需要从0号位置开始spfa一次就好啦。

2.选择邻接表存储图。(如果亲爱的读者大宝贝,邻接表忘记怎么实现的话,巴啦啦能量---->点我,我是邻接表的详解

3.spfa模板。(其实不需要模板的,spfa和bfs差不多的,如果你忘了的话,巴啦啦能量×2---->点我,我是spfa未优化的模板

所以实现如下:

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int MaxnEdge = 21010;
const int MaxnV = 1010;
const int INF = 0x3f3f3f3f;
int n, m, s;
int visit[MaxnV];
int dis[MaxnV];
int u[MaxnEdge], v[MaxnEdge], w[MaxnEdge];
int first[MaxnEdge], Next[MaxnEdge];
void spfa(int start){
    memset(visit, 0, sizeof(visit));
    memset(dis, 0x3f, sizeof(dis));
    queue<int>q;
    while (!q.empty())
        q.pop();
    q.push(start);
    visit[start] = 1;
    dis[start] = 0;
    while (!q.empty()){
        int now = q.front();
        q.pop();
        visit[now] = 0;
        for (int i = first[now]; i != -1; i = Next[i]){
            if (dis[v[i]] > dis[now] + w[i]){
                dis[v[i]] = dis[now] + w[i];
                if (!visit[v[i]]){
                    q.push(v[i]);
                    visit[v[i]] = 1;
                }
            }
        }
    }
}
int main(){
    while (scanf("%d%d%d", &n, &m, &s)!= EOF){
        memset(first, -1, sizeof(first));
        memset(Next, -1, sizeof(first));
        for (int i = 0; i < m; i++){
            scanf("%d%d%d", &u[i], &v[i], &w[i]);
            Next[i] = first[u[i]];
            first[u[i]] = i;
        }
        int ncase;
        scanf("%d", &ncase);
        for (int i = 0; i < ncase; i ++){
            int to;
            scanf("%d", &to);
            v[i + m] = to;
            w[i + m] = 0;
            Next[i + m] = first[0];
            first[0] = i + m;
        }
        spfa(0);
        if (dis[s] == INF){
            printf("-1\n");
        }
        else
            printf("%d\n", dis[s]);
        //for (int i = first[0]; i != -1; i = Next[i])
        //    printf("%d\%d\%d\n", u[i], v[i], w[i]);

    }
    return 0;
}


细心的读者大宝贝,你一定发现了一些猫腻,那就是:

1.MaxnEdge = 21010;这是因为总边数=题目输入边数+与0号位置相连的边数。

2.Next数组的首字母大写了,为什么不是next数组呢?【强迫症如我】

原因是CE了,可能next在HDU的编译器上是关键字好像:


改成Next就AC了,奇怪而又有趣是吧:


3.在初始化dis数组的时候,要初始化最大值,const int INF=0x7fffffff;并不是最好的选择;最好的选择是const int INF = 0x3f3f3f3f;还可以用memset初始化:memset(dis, 0x3f, sizeof(dis));

附一下memset初始化的大佬解释:巴啦啦能量×3----->点我呀,我是memset我很皮


好了,昨天发现数据结构的网课TMD第五周的作业提交截止时间过了,很难受,所以今天没有表情包。

不过今天还是得皮一下:

沿着你皮肤纹理,走过曲折手臂

目光所及,是你发际

让我陷入这黑色的沼泽

心甘情愿地赴死

在你的瞳孔里看到自己的眼睛

在你的呼吸里找到自己的气息

在你的眉宇间闪躲自己的思念

在你的身体里找到另一个自己

我爱你

从左心房到右心室

从心脏到喉咙

从血液到灵魂


2018年4月17日晚0:10

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值