迪杰斯特拉与spfa

比较全的一个博客
https://www.cnblogs.com/wozuishuaiwozuiniu6/p/13178762.html

spfa
SPFA 算法是 Bellman-Ford算法 的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环。SPFA 最坏情况下复杂度和朴素 Bellman-Ford 相同,为 O(VE)。

洛谷P1462 【通往奥格瑞玛的道路】

再被题面军搞懵一阵子后发现这貌似是一个求最大值最小的问题(还真是)。

哦,找上界嘛,使这个上界在能跑到n点的情况下尽可能的小,当然上界就是f [i] 啦。可以加一个mon数组,排遍序,二分比较方便。

二分答案套模板,把judge换成spfa版,具体看代码,框架是二分答案的架子,主体是spfa。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#include<cmath>
using namespace std;
queue <int> que;
struct Edge{
    int next;
    int to;
    int key;
}edge[100005];
int cnt=0,head[50001],n,m,b,f[50001],mon[50001],r,l,mid,ans;
long long dis[50001];
bool vis[50001];
int read()
{
    int r=0,k=1;
    char c=getchar();
    for(;c<'0'||c>'9';c=getchar())if(c=='-')k=-1;
    for(;c>='0'&&c<='9';c=getchar())r=r*10+c-'0';
    return r*k;
}
void add(int x,int y,int z)
{
    ++cnt;
    edge[cnt].next=head[x];
    head[x]=cnt;
    edge[cnt].to=y;
    edge[cnt].key=z;
}
bool spfa(int sj)
{
    memset(dis,0x7f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[1]=0;
    vis[1]=1;
    que.push(1);
    while(!que.empty())
    {
        int x=que.front();
        que.pop();
        vis[x]=0;
        for(int i=head[x];i;i=edge[i].next)
        {
            int will=edge[i].to;
            if(f[will]>sj) continue;
            if(dis[x]+edge[i].key<dis[will])
            {
                dis[will]=dis[x]+edge[i].key;
                if(!vis[will])
                {
                    vis[will]=1;
                    que.push(will);
                }
            }
        }
    }
    if(dis[n]>=b||dis[n]==dis[0]) return 0;
    else return 1;
}
int main()
{
    n=read();
    m=read();
    b=read();
    for(int i=1;i<=n;i++) mon[i]=f[i]=read();
    sort(mon+1,mon+1+n);
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        x=read();
        y=read();
        z=read();
        add(x,y,z);
        add(y,x,z);
    }
    l=1,r=n;
    if(!spfa(1000000001))
    {
        cout<<"AFK"<<endl;
        return 0;
    }
    while(l<=r)
    {
        mid=(l+r)>>1;//二分金钱 
        if(spfa(mon[mid]))//看看在此情况下,血量是否允许 
        {
            r=mid-1;
            ans=mon[mid];
        }
        else l=mid+1; 
    }
    cout<<ans<<endl;
    return 0;
}

迪杰斯特拉
时间复杂是 O(n2+m)O(n2+m), nn 表示点数,mm 表示边数

int g[N][N];  // 存储每条边
int dist[N];  // 存储1号点到每个点的最短距离
bool st[N];   // 存储每个点的最短路是否已经确定

// 求1号点到n号点的最短路,如果不存在则返回-1
int dijkstra()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;

    for (int i = 0; i < n - 1; i ++ )
    {
        int t = -1;     // 在还未确定最短路的点中,寻找距离最小的点
        for (int j = 1; j <= n; j ++ )
            if (!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;

        // 用t更新其他点的距离
        for (int j = 1; j <= n; j ++ )
            dist[j] = min(dist[j], dist[t] + g[t][j]);

        st[t] = true;
    }

    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值