题解 洛谷P1462 通往奥格瑞玛的道路

本文分享了洛谷P1462【通往奥格瑞玛的道路】题解,作者独立完成的首个二分答案题目。文章详细解析了题目理解的重要性,介绍了如何通过二分答案求解最大值的最小值问题,并附上了完整的代码实现。

题解 P1462 【通往奥格瑞玛的道路】

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

本题是本人第一个在没有任何人的指导下完成的二分答案的题。

所以发一个题解纪念一下。

题目理解很重要…

而且有一个条件就是,当血量低于0时(其实也是包含0的)就不能到达了。

题目一看是求最大值的最小值或者是求最小值的最大值便科知道要使用二分答案来求解了

下面附上我的代码

#include<bits/stdc++.h>
using namespace std;/*
4 4 8
8
5
6
10
2 1 2
2 4 1
1 3 4
3 4 3
*/
const int N=11000;
const int M=51000;
const int inf=1e9+7;
struct edge
{
    int to,next,val;
}mem[M<<1];//因为是无向图所以要开双向边,所以要开大一倍 
int n,m,u,v,cnt=1,b,val,maxn=-1;
int head[M<<1],a[N],d[N];
bool vis[N];
inline void read(int &x)//读入优化 
{
    x=0;
    bool flag=0;
    char ch=getchar();
    while('0'>ch||ch>'9')
    {
        if(ch=='-')
            flag=1;
        ch=getchar();
    }
    while('0'<=ch&&ch<='9')
    {
        x=(x<<3)+(x<<1)+ch-'0';//据说两次位运算的速度也要比直接x*10要快 
        ch=getchar();
    }
    if(flag)
        x=-x;
}
inline void add(int u,int v,int val)//链式前向星存图 
{
    mem[++cnt].next=head[u];
    mem[cnt].to=v;
    mem[cnt].val=val;
    head[u]=cnt;
}
inline bool spfa(int maxn)//普通的spfa算法求最短路,所经过的所有点的点权都不能大于(<=)maxn 
{//具体的spfa的解释就不再这里说了,若有想具体了解spfa的
//请详见[洛谷P3371单元最短路径](https://www.luogu.org/problemnew/show/P3371)
    for(int i=1;i<=n;i++)
        vis[i]=0,d[i]=inf;
    queue<int> q;
    while(!q.empty())
        q.pop();
    d[1]=0,vis[1]=1;
    q.push(1);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        if(a[x]>maxn)//点的点权都不能大于(<=)maxn 
            continue; 
        for(int e=head[x];e;e=mem[e].next)
        {
            int to=mem[e].to;
            if(a[to]>maxn)//点的点权都不能大于(<=)maxn 
                continue;
            if(d[to]>d[x]+mem[e].val)
            {
                d[to]=d[x]+mem[e].val;
                if(!vis[to])
                {
                    vis[to]=1;
                    q.push(to);
                }
            }
        } 
        vis[x]=0;
    }
    //cout<<"maxn="<<maxn<<" d[n]="<<d[n]<<endl;
    if(b>d[n])//如果血量=0或血量<0就不能到达,即掉的最少的血的数目d[n]<b 
        return 1;//答案不可以是maxn 
    return 0;//否则答案可以是maxn 
}
int main()
{
    read(n),read(m),read(b);
    for(int i=1;i<=n;i++)
    {
        read(a[i]);
        maxn=max(maxn,a[i]);//确认二分答案的上限 
    }
    for(int i=1;i<=m;i++)
    {
        read(u),read(v),read(val);
        add(u,v,val);//因为是无向图,所以要建立双向的边 
        add(v,u,val);
    }
    if(!spfa(maxn))//如果将点权最大的点取上都不能到达,则永远不可能达到 
    {
        puts("AFK");
        return 0;
    }
    int l=0,r=maxn;//二分答案,因为答案的边界可能是[0,maxn]的闭区间 
    while(l<=r)
    {
        int mid=l+r>>1;//因为位运算的优先级低于l+r,所以此处打不打括号均可(建议还是打上比较好) 
        if(!spfa(mid))//最大点权为maxn不能达到 
            l=mid+1;
        else//最大点权为maxn可以达到 
            r=mid-1;
    }
    printf("%d\n",l);//输出答案即交费最多的一次的最小值 
    return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值