2/1 最短路径和链式前向星的结合应用

Posted 钟钟终

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2/1 最短路径和链式前向星的结合应用相关的知识,希望对你有一定的参考价值。

首先写第三点,我觉得是最重要的,dijkstra算法的优化,从复杂度O(n方)复杂度降到

算是最佳的最短路径方法,非常稳定。下面是代码

#include <bits/stdc++.h>

using namespace std;
const int maxn=200005;
typedef long long ll;
const int inf=0x7fffffff;
struct node

    int to,dis,nxt;
e[1000005];
int head[maxn],n,m,s,t,u,v,w,nxt,cnt;
ll dist[maxn],minn;
bool vis[maxn];
void add_edge(int from,int to,int dis)

    e[++cnt].to=to;
    e[cnt].dis=dis;
    e[cnt].nxt=head[from];
    head[from]=cnt;


struct node1

    int dis,pos;
    bool operator <(const node1 &x)const
    
        return x.dis<dis;
    
;
std::priority_queue<node1>q;
void dijkstra()

    dist[s]=0;
    q.push((node1)0,s); //到该点的距离为0,位置为点s
    while(!q.empty())
    
        node1 cur=q.top();
        q.pop();
        int x=cur.pos,d=cur.dis;
        if(vis[x]) continue;
        vis[x]=1;
        for(int i=head[x];i!=-1;i=e[i].nxt)
        
            int y=e[i].to;
            if(dist[y]>dist[x]+e[i].dis)
            
                dist[y]=dist[x]+e[i].dis;
                if(!vis[y])
                
                    q.push((node1)dist[y],y);
                
            
        
    

int main()

    scanf("%d%d%d",&n,&m,&s);
    head[0]=-1;
    for(int i=1;i<=n;i++)
    
        dist[i]=inf;
        head[i]=-1;
    
    for(int i=1;i<=m;i++)
    
        scanf("%d%d%d",&u,&v,&w);
        add_edge(u,v,w);
    
    dijkstra();
    for(int i=1;i<=n;i++)
        printf("%lld ",dist[i]);
    printf("\\n");
    return 0;

1.给一个dijkstra算法的基本模板(大多数不适用,因为数据范围太大,超过10000那么二维数组就会超出范围,因此要使用链式前向星的方法,使用范围很小)
https://www.luogu.com.cn/problem/P1339

#include <bits/stdc++.h>

using namespace std;
const int maxn=2505;
const int inf=0x7fffffff;
int dist[maxn],mp[2*maxn][2*maxn],minn,n,m,s,t,u,v,w,nxt;
bool vis[maxn];
int main()

    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(int i=1;i<=n;i++)
    
        dist[i]=inf;
        for(int j=1;j<=n;j++)
            mp[i][j]=inf;
    
    for(int i=1;i<=m;i++)
    
        scanf("%d%d%d",&u,&v,&w);
        mp[u][v]=min(mp[u][v],w);
        mp[v][u]=mp[u][v];
    
    dist[s]=0;
    vis[s]=1;
    while(s!=t)
    
        minn=inf;
        for(int i=1;i<=n;i++)
        
            if(mp[s][i]!=inf)
            
                dist[i]=min(dist[i],mp[s][i]+dist[s]);
            
            if(!vis[i]&&dist[i]<minn)
            
                nxt=i;
                minn=dist[i];
            
        
        if(minn==inf) break;
        s=nxt;vis[s]=1;
    
    printf("%d\\n",dist[t]);
    return 0;

2.最短路径和链式前向星的结合应用,模板的修改
https://www.luogu.com.cn/problem/P3371

//每次是对于一条链进行操作,因此不能像模板那样一层层处理,不对,也是一层层处理,只是连了起来

#include <bits/stdc++.h>

using namespace std;
const int maxn=20005;
typedef long long ll;
const int inf=0x7fffffff;
struct node

    int to,dis,nxt;
e[1000005];
int head[maxn],n,m,s,t,u,v,w,nxt,cnt;
ll dist[maxn],minn;
bool vis[maxn];
void add_edge(int from,int to,int dis)

    e[++cnt].to=to;
    e[cnt].dis=dis;
    e[cnt].nxt=head[from];
    head[from]=cnt;

int main()

    scanf("%d%d%d",&n,&m,&s);
    head[0]=-1;
    for(int i=1;i<=n;i++)
    
        dist[i]=inf;
        head[i]=-1;
    
    for(int i=1;i<=m;i++)
    
        scanf("%d%d%d",&u,&v,&w);
        add_edge(u,v,w);
    
    dist[s]=0;
    while(!vis[s])
    
        vis[s]=1;
        minn=inf;
        for(int i=head[s];i!=-1;i=e[i].nxt)  //每次是对于一条链进行操作,因此不能像模板那样一层层处理
        
            if(dist[e[i].to]>e[i].dis+dist[s]&&!vis[e[i].to])
            
                dist[e[i].to]=e[i].dis+dist[s];
            
        
        for(int i=1;i<=n;i++)
        
            if(!vis[i]&&minn>dist[i])
            
                minn=dist[i];
                s=i;
            
        
    
    for(int i=1;i<=n;i++)
        printf("%lld ",dist[i]);
    printf("\\n");
    return 0;

3.从1开始到各点的最短路径+各个点到1的最短路径之和要最小:
处理方案:
从1开始到各点的最短路径没什么好说的;
各个点到1的最短路径之和要最小:需要反向存图,在用dijkstra算法从1到各点的累加和,跑两遍算法,可举几个例子加深理解,都是符合的
https://www.luogu.com.cn/problem/P1342
巧妙应用函数传递,注意全局变量和数组的清零。

#include <bits/stdc++.h>

using namespace std;
const int maxn=1000005;
typedef long long ll;
const int inf=0x7fffffff;
struct node

    int to,dis,nxt;
e[maxn],e1[maxn];
int head[maxn],n,m,s,t,u,v,w,nxt,cnt,cnt1,head1[maxn];
ll dist[maxn],minn,ans,dist1[maxn];
bool vis[maxn];
void add_edge(int from,int to,int dis)

    e[++cnt].to=to;
    e[cnt].dis=dis;
    e[cnt].nxt=head[from];
    head[from]=cnt;

void add_edge1(int from,int to,int dis)

    e1[++cnt1].to=to;
    e1[cnt1].dis=dis;
    e1[cnt1].nxt=head1[from];
    head1[from]=cnt1;

struct node1

    int dis,pos;
    bool operator <(const node1 &x)const
    
        return x.dis<dis;
    
;
std::priority_queue<node1>q;
void dijkstra(ll dist[],node e[],int head[])

    dist[s]=0;
    q.push((node1)0,s); //到该点的距离为0,位置为点s
    while(!q.empty())
    
        node1 cur=q.top();
        q.pop();
        int x=cur.pos,d=cur.dis;
        if(vis[x]) continue;
        vis[x]=1;
        for(int i=head[x];i!=-1;i=e[i].nxt)
        
            int y=e[i].to;
            if(dist[y]>dist[x]+e[i].dis)
            
                dist[y]=dist[x]+e[i].dis;
                if(!vis[y])
                
                    q.push((node1)dist[y],y);
                
            
        
    

int main()

    scanf("%d%d",&n,&m);
    head[0]=-1;head1[0]=-1;
    for(int i=1;i<=n;i++)
    
        dist[i]=inf;
        dist1[i]=inf;
        head[i]=-1;
        head1[i]=-1;
    
    for(int i=1;i<=m;i++)
    
        scanf("%d%d%d",&u,&v,&w);
        add_edge(u,v,w);
        add_edge1(v,u,w);
    
    s=1;
    dijkstra(dist,e,head);
    memset(vis,0,sizeof(vis));
    s=1;
    dijkstra(dist1,e1,head1);
    for(int i=1;i<=n;i++)
        ans+=dist1[i],ans+=dist[i];
    printf("%lld\\n",ans);
    return 0;


以上是关于2/1 最短路径和链式前向星的结合应用的主要内容,如果未能解决你的问题,请参考以下文章

SPFA_queue_链式前向星最短路 & HDU2433

hdu-3790最短路刷题

tarjan缩点以及链式前向星的基本+应用(洛谷1262 间谍网络)

最短路 SPFA()链式前向星

最短路Dijkstra+ 链式前向星+ 堆优化(优先队列)

UESTC30-最短路-Floyd最短路spfa+链式前向星建图