洛谷【模板】单源最短路径

【模板】单源最短路径(弱化版) - 洛谷

【模板】单源最短路径(标准版) - 洛谷

先来弱化版。

df94cf5560774015b9ce09417739a763.png

fe9d2b5ff99047d48220edebcb64e641.png  

这道题数据范围给的不是很大,所以可以开邻接矩阵试试。

提示:两个点之间可能有多条边。要是有两个同向的边我能选更长的

 MLE代码(Floyd+邻接矩阵)(20分)

#include <bits/stdc++.h>
using namespace std;

int e[10001][10001];
int n,m,s,u,v,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(e[i][j]>e[i][k]+e[k][j]){
                    e[i][j]=e[i][k]+e[k][j];
                }
            }
        }
    }
}
inline void scan(){
    cin>>n>>m>>s;
    for(int i=1;i<=m;i++){
        for(int j=1;j<=m;j++){
            if(i!=j)e[i][j]=INT_MAX/2;
        }
    }

    for(int i=1;i<=m;i++){
        cin>>u>>v>>w;
        e[u][v]=min(w,e[u][v]);
    }
}
int main(){
    cin.tie(nullptr),cout.tie(nullptr);
    ios::sync_with_stdio(false);
    scan();

    floyd();

    for(int i=1;i<=n;i++){
        if(e[s][i]!=INT_MAX/2)cout<<e[s][i]<<" ";
        else cout<<INT_MAX<<" ";
    }
    return 0;
}

Floyd算法传送门:https://www.cnblogs.com/11sgXL/p/13644680.html

MLE原因很简单,算了一下内存,1亿的数组爆炸了,题目限制125MB,数组占了381.47MB,这样都给了20分(感叹)。

用邻接表或者向前星来实现Floyd就会变得很麻烦,要先遍历一遍,所以这道题PASS掉Floyd和邻接矩阵

那么接下来试试常规套餐,邻接表+Dijkstra算法。

AC代码(邻接表+Dijkstra算法)

#include <bits/stdc++.h>
using namespace std;

int n,m,s,dist[10001];
vector<pair<int,int>>e[10001];//距离->编号
bitset<10001>vis;
inline void scan(){
    cin>>n>>m>>s;
    int u,v,w;
    for(int i=0;i<m;i++){
        cin>>u>>v>>w;
        e[u].push_back({w,v});
    }
}
//定义dist[i]为i节点到s节点的最短距离
inline void dijkstra(){
    //初始化
    for(int i=1;i<=n;i++)
        dist[i]=INT_MAX/2;
    dist[s]=0;//自己到自己为0

    //贪心
    for(int i=1;i<=n;i++){
        int idx=-1;
        //在dist中找最短距离
        for(int j=1;j<=n;j++){
            //任意第一个
            if(idx==-1&&!vis[j])idx=j;
            //更小的
            if(idx!=-1&&!vis[j]&&dist[j]<dist[idx])idx=j;
        }

        vis[idx]=true;
        //更新和idx相关的dist
        for(auto j:e[idx]){
            dist[j.second]=min(dist[j.second],j.first+dist[idx]);
        }
    }
}

int main(){
    cin.tie(nullptr),cout.tie(nullptr);
    ios::sync_with_stdio(false);
    scan();

    dijkstra();

    for(int i=1;i<=n;i++)
        if(dist[i]==INT_MAX/2)cout<<INT_MAX<<" ";
    else cout<<dist[i]<<" ";
    return 0;
}

果然是弱化版啊(感叹),里面用INT_MAX/2而不用INT_MAX是为了防止某个数加上dist会导致溢出出现负数。

拿弱化版的代码去跑一下标准版试试(喜),Dijkstra算法甚至都还没用上配套的堆优化,因为选点是O(n),但是我们一直都在选最小的那一个head,也就是说可以用小根堆来优化成O(logn)。


标准版

5cb5f94a9f3946c79695ef6f446d481d.png

d0a8ed72098b40b1be594b70ff6fe1ff.png

54c7ac077fb946eeaa52b2867beb7d77.png

什么都没看直接提交喜提RE。

bdaad34e4bd74744b36a1430520a5257.png

一看数组范围多扩大了十倍,没有优先队列优化多半要TLE几个点,所以我选择直接吸氧。 

然后喜提6个TLE

5bf1308193fd40318b8ba3f1a7e1ce10.png

O2TLE代码(邻接表+Dijkstra算法)照抄弱化版原文

#include <bits/stdc++.h>
using namespace std;

int n,m,s,dist[100001];
vector<pair<int,int>>e[100001];//距离->编号
bitset<100001>vis;
inline void scan(){
    cin>>n>>m>>s;
    int u,v,w;
    for(int i=0;i<m;i++){
        cin>>u>>v>>w;
        e[u].push_back({w,v});
    }
}
//定义dist[i]为i节点到s节点的最短距离
inline void dijkstra(){
    //初始化
    for(int i=1;i<=n;i++)
        dist[i]=INT_MAX/2;
    dist[s]=0;//自己到自己为0

    //贪心
    for(int i=1;i<=n;i++){
        int idx=-1;
        //在dist中找最短距离
        for(int j=1;j<=n;j++){
            //任意第一个
            if(idx==-1&&!vis[j])idx=j;
            //更小的
            if(idx!=-1&&!vis[j]&&dist[j]<dist[idx])idx=j;
        }

        vis[idx]=true;
        //更新和idx相关的dist
        for(auto j:e[idx]){
            dist[j.second]=min(dist[j.second],j.first+dist[idx]);
        }
    }
}

int main(){
    cin.tie(nullptr),cout.tie(nullptr);
    ios::sync_with_stdio(false);
    scan();

    dijkstra();

    for(int i=1;i<=n;i++)
        if(dist[i]==INT_MAX/2)cout<<INT_MAX<<" ";
    else cout<<dist[i]<<" ";
    return 0;
}

既然如此那也只能用优先队列来优化选点了。

这么强悍的时间我估计不吸氧气都能过= =

56308cbbbf7e4c748d00e58b665c4fb1.png

O2AC代码(邻接表+Dijkstra算法+优先队列)

#include <bits/stdc++.h>
using namespace std;

//小根堆
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>q;
int n,m,s,dist[100001];
vector<pair<int,int>>e[100001];//距离->编号
bitset<100001>vis;
inline void scan(){
    cin>>n>>m>>s;
    int u,v,w;
    for(int i=0;i<m;i++){
        cin>>u>>v>>w;
        e[u].push_back({w,v});
    }
}
//定义dist[i]为i节点到s节点的最短距离
inline void dijkstra(){
    //初始化
    for(int i=1;i<=n;i++)
        dist[i]=INT_MAX/2;
    dist[s]=0;//自己到自己为0

    //优先队列选点
    q.push({0,s});
    while(!q.empty()){
        int now=q.top().second;
        int nowDis=q.top().first;
        q.pop();//要在新节点加入前就pop

        if(vis[now])continue;
        vis[now]=true;
        for(auto i:e[now]){
            int toNextLength=i.first;
            int nxt=i.second;

            if(dist[nxt]>dist[now]+toNextLength){
                dist[nxt]=dist[now]+toNextLength;
                if(!vis[nxt]){
                    q.push({dist[nxt],nxt});
                }
            }
        }
    }
}

int main(){
    cin.tie(nullptr),cout.tie(nullptr);
    ios::sync_with_stdio(false);
    scan();

    dijkstra();

    for(int i=1;i<=n;i++)
        if(dist[i]==INT_MAX/2)cout<<INT_MAX<<" ";
    else cout<<dist[i]<<" ";
    return 0;
}

几道和模板题差不多的题:采购特价商品 - 洛谷Mzc和体委的争夺战 - 洛谷

e497c1d567ee4894bd81d4b5de8c874f.png

不过要注意的是用优先队列选点的时候如果vis[now]=true的时候就不用再去找他了,否则喜提TLE。

稍微难了一点的题:[USACO07FEB] Cow Party S - 洛谷

不过也就是正向dj一次加上反向dj一次。

类似的题目有很多,可以点算法标签最短路找,代码就不帖了。

以及转变思维的最小花费 - 洛谷

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值