Dijkstra算法和SPFA算法

P4779 【模板】单源最短路径(标准版)

/*
思路:
用链式向前星存储顶点之间的关系与权值
用优先队列存储边权小的先出
首先将起点入队,向四周发散,再将起点与到达点的总权值入队,
保证了是一步一步到达(如果不连通不可能遍历到),同时遍历的过程当中不断找更小的权值并更新
优先队列的用处:若有两种不同的到达方式,优先队列会先遍历到短的那一条,然后将其入队,那远的一条就不会入队。


*/
#include <bits/stdc++.h>
using namespace std;
const int N=5e5+10,M=2e5+10;
int n,m,s,x,y,z,cnt,vis[N],head[N];
long long dis[N];
struct edge
{
    int w,to,next;
}e[N];
void add(int x,int y,int z)
{
    e[++cnt].to=y;
    e[cnt].w=z;
    e[cnt].next=head[x];
    head[x]=cnt;
}
struct node
{
    int  u,w;
};
bool operator < (const node &s1,const node &s2)//重载运算符,优先队列中的自定义排序
{return s1.w>s2.w;}//注意写大于号还是小于号与实际的符号相反,实际是小于号,则要写大于号
priority_queue<node>q;
void  dij()
{
    q.push({s,0});
    dis[s]=0;
    while(!q.empty())
    {
        int u=q.top().u;q.pop();
        if(vis[u])continue;
        vis[u]=1;
        //遍历所有以u为起点的边
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            int v=e[i].to;
            //dis[u]为起点到u的权值,e[i].w是u到v的权值,dis[v]是起点到v的权值
            if(dis[u]+e[i].w<dis[v])
            {
                dis[v]=dis[u]+e[i].w;
                q.push((node){v,dis[v]});
            }
        }
    }
}

int main()
{
    cin>>n>>m>>s;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=m;i++)
    {
        scanf("%d %d %d",&x,&y,&z);
        add(x,y,z);
    }
    for(int i=0;i<=n;i++)
      dis[i]=2147483647;
    dij();
    for(int i=1;i<=n;i++)
        printf("%lld ",dis[i]);
    return 0;
}

P1186 玛丽卡

思路就是将最短路上的路径遍历一遍,都堵一次,找花费时间最大的。

/*
思路:
用链式向前星存储顶点之间的关系与权值
用优先队列存储边权小的先出
首先将起点入队,向四周发散,再将起点与到达点的总权值入队,
保证了是一步一步到达(如果不连通不可能遍历到),同时遍历的过程当中不断找更小的权值并更新
优先队列的用处:若有两种不同的到达方式,优先队列会先遍历到短的那一条,然后将其入队,那远的一条就不会入队。


*/
#include <bits/stdc++.h>
using namespace std;
const int N=1e3+10,M=2e5+10;
int n,m,s,x,y,z,cnt,vis[N],head[N],st,ed,flag;
int dis[N],last[N];
struct edge
{
    int w,to,next;
}e[N*N];
void add(int x,int y,int z)
{
    e[++cnt].to=y;
    e[cnt].w=z;
    e[cnt].next=head[x];
    head[x]=cnt;
}
struct node
{
    int  u,w;
};
bool operator < (const node &s1,const node &s2)//重载运算符,优先队列中的自定义排序
{return s1.w>s2.w;}//注意写大于号还是小于号与实际的符号相反,实际是小于号,则要写大于号
priority_queue<node>q;
void  dij()
{
    memset(vis,0,sizeof(vis));
    for(int i=0;i<=n;i++)
      dis[i]=2147483647;
    q.push({s,0});
    dis[s]=0;
    while(!q.empty())
    {
        int u=q.top().u;q.pop();
        if(vis[u])continue;
        vis[u]=1;
        //遍历所有以u为起点的边
        for(int i=head[u];i!=-1;i=e[i].next)
        {

            int v=e[i].to;
            if(u==st&&v==ed)continue;
            //dis[u]为起点到u的权值,e[i].w是u到v的权值,dis[v]是起点到v的权值
            if(dis[u]+e[i].w<dis[v])
            {
                if(!flag)last[v]=u;
                dis[v]=dis[u]+e[i].w;
                q.push((node){v,dis[v]});
            }
        }
    }
}

int main()
{
    cin>>n>>m;
    s=1;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
        add(y,x,z);
    }
    dij();
    int ans=0;
    ed=n;
    flag=1;
    while(ed!=1)
    {
        st=last[ed];

        s=1;
        dij();
        ans=max(ans,dis[n]);
        ed=st;
    }
    cout<<ans<<endl;
    return 0;
}

P1462 通往奥格瑞玛的道路

题目的关键词“最大最小值”,一看就是二分的题,二分大小,满足即可右区间调左,不满足则左区间右移,第一次没做出来,日后复习再做。

猜你喜欢

转载自blog.csdn.net/zhoucheng_123/article/details/107581176
今日推荐