0
点赞
收藏
分享

微信扫一扫

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

夹胡碰 2022-02-01 阅读 73
图论算法

首先写第三点,我觉得是最重要的,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;
}

举报

相关推荐

0 条评论