最短路刷题感想以及模板

感想:

感想?不敢想不敢想。

刷了一整个最短路专题,其中大部分都是kuangbin带我飞系列的题

期间写了无数个神奇的bug

也曾经通宵调bug(摸鱼)过,暑训的快感来源于此

为了避免之后再踩同样的坑、总结出了一点点模板

还有自己对最短路里面各个算法的一点点体会

1.floyd

目测是最简单的最短路算法吧

3个for 的复杂度爆炸的算法

不过用来写一些数据量特别小的题还是特别舒服的

代码如下:

const int maxn = 1005;
int dis[maxn][maxn];

void floyd(){
    for(int k=0;k<n;k++){
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                if(dis[i][j]>dis[i][k]+dis[k][j]){
                    dis[i][j]=dis[i][k]+dis[k][j];
                }
            }
        }
    }
}
/*
floyd的邻接矩阵的用法
n表示顶点个数
dis[i][j]表示从点i到点j的权值大小
复杂度为O(n^3),emmm数据在100、200之间的题可以用
作为最短路入门了
*/
View Code

2.dijkstra

这个就稍微有难度了

一开始都是对着板子写题,其实刷题刷多了,这个算法的套路也了解了

复杂度是E*O(V)的 边乘以点

经过优先队列的优化后甚至可以达到nlog(n)的级别

思想也很简单,像最小生成树的kruskal的算法一样,我们都是从起始点出发

找距离最短/最长的边,加入队列,一个个进行比较的

最后可以打出来一个dis的表(emmm大佬别打我,我理解的dis是一个表,如果有错,麻烦指出

这个dis的表的意义就是从起点到各个点的最短/最长的距离的集合

于是我们就可以得到单源每一个点到各个点的最短路

所以dijkstra适合用于单源最短路的情况

但是不适合有负权环的情况 

代码如下:

const int maxn =  1005;
int mp[maxn][maxn]
bool vis[maxn];
int  dis[maxn];
int dijkstra(int st,int ed){
    vis[st]=1;
    for(int i=1;i<=n;i++){
        dis[i]=mp[1][i];
    }
    int x,minn;
    for(int i=1;i<=n;i++){
        minn=INF;
        for(int j=1;j<=n;j++){
            if(!vis[j]&&minn>dis[j]){
                minn=dis[j];
                x=j;
            }
            vis[x]=1;
            for(int j=1;j<=n;j++)}{
                if(dis[j]>dis[x]+mp[x][j]){
                    dis[j]=dis[k]+mp[x][j];
                }
            }
    }
    return dis[ed];
}
/*
dijsktra的邻接矩阵的用法,
n表示顶点个数
其中mp是邻接矩阵的存图,
vis是是否走过的标记
dis是从起点出发到点i距离的最小/最大值
mp、dis初始化为INF
注意题目如果有重边的话需要处理一下
*/
View Code
const int maxn = 1005;
typedef pair<double,int>Pair;
int dis[maxn];
bool vis[maxn];
void dijkstra(int st){
    memset(dis,INF,sizeof(dis));
    memset(vis,0,sizeof(vis));
    priority_queue(P,vector<P>,greater<P> ) q;
    d[st]=0;
    q.push(P(0,st));
    while(!q.empty()){
        int x=p.top().second;
        q.pop();
        if(vis[x]) continue;
        vis[x] = 1;
        for(int i = 1; i <= n; i++) {
            if(dis[i] > dis[x] + mp[x][i]) {
                dis[i] = dis[x] + mp[x][i];
                q.push(make_pair(dis[i], i));
            }
        }
    }
}
View Code

3.spfa

spfa和bfs算法很像、把可以走的点丢进队列里面,然后每一个都走到不能走为止

然后就可以得到最短路了

因为是从起点到后面所有的点,可以适用于多源最短路的处理情况

我暂时实现了普通的队列版本、手动模拟队列的版本、堆栈的版本待更新

(听说手写堆会特别快

我建图习惯前向星建图(不容易被POJ卡

代码如下:

const int maxn = 1e5+5;
struct node{
    int to,next,w;
}edge[maxn];
int head[maxn];
bool vis[maxn];
int t=0;
void add(int u,int v,int w){
    edge[t].to=v;
    edge[t].w=w;
    edge[t].next=head[u];
    head[u]=t++;
}
void spfa(int st){
//spfa还可以用堆栈、模拟队列来写,貌似会快一些
    memset(vis,0,sizeof(vis));
    memset(dis,INF,sizeof(dis));
    queue<int> q;
    q.push(st);
    vis[st]=1;
    dis[st]=0;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(dis[v]>dis[u]+edge[i].w){
                dis[v]=dis[u]+edge[i].w;
            }
            if(!vis[v]){
                vis[v]=1;
                q.push(v);
            }
        }
    }
}
/*
spfa算法
其中n代表顶点个数
dis[i]代表从起点出发到达i点的最短/最长(依据实际情况而定)距离
vis[i]代表i这个点是否走过
用邻接表的前向星写法有助于存储边多点少的图
用head表示上一个节点
输入之前记得将head初始化为-1
*/
View Code
const int maxn = 1e5+5;
struct node{
    int to,next,w;
}edge[maxn];
int head[maxn];
int q[maxn];  //用数组来模拟队列貌似会快一点点
bool vis[maxn];
int t=0;
void add(int u,int v,int w){
    edge[t].to=v;
    edge[t].w=w;
    edge[t].next=head[u];
    head[u]=t++;
}
void spfa(int st){
    memset(vis,0,sizeof(vis));
    memset(dis,INF,sizeof(dis));
    queue<int> q;
    q.push(st);
    vis[st]=1;
    dis[st]=0;
    q[0]=st;
    int top=1;
    while(top!=0){
        top--;
        int u=q[top];
        vis[u]=0;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(dis[v]>dis[u]+edge[i].w){
                dis[v]=dis[u]+edge[i].w;
            }
            if(!vis[v]){
                vis[v]=1;
                q[top++]=v;
            }
        }
    }
}
/*
spfa算法用模拟队列实现
其实就只是用数组模拟队列
稍微改了一点点,随缘减少常数吧应该还是
嘤嘤嘤
*/
View Code

最短路最重要的还是建图

要有读题后把题目抽象成图形的能力

所以需要多刷题  遇见各种各样类型的题目才好

学习kuangbin大神的

人一我十,人十我万!

不停的奋斗吧,给凌晨的自己一碗鸡汤

猜你喜欢

转载自www.cnblogs.com/buerdepepeqi/p/9393712.html