OJ笔记 18718 航行

18718 航行

Description
银河帝国正走向覆亡。为保留文明的种子,你需要驾驶飞船将一批“颛家”从帝国首都护送至银河边缘的基地。
现在已知航线是一条直线,帝国首都为起点(坐标0),基地为终点(坐标L),在这条航线上有N个空间站可以补充飞船的能源。
第i个空间站的坐标为ai,飞船停靠在第i个空间站必须花费bi个银河币,同时让你的飞船能量恢复为最大值M。
出发前飞船的能量是满额的M,每一点能量都可以让飞船航行一个坐标单位。

现在你已经通过募捐(榨篇)获得了S个银河币,请计算下飞船能否到达基地。

输入格式
第一行输入四个个数字N,L,M,S;(1<=N<=200) (1<=L<=20000) (1<=M<=20000) (0<=S<=20000)
接下来N行,每行输入两个数字,ai,bi (0<=ai<=L) (0<=bi<=20000)

输出格式
仅一行,如果能到达基地,输出Yes,否则输出No

输入样例
1 10000 5000 20000
5000 20000

输出样例
Yes

提示
样例说明,飞船可以花费5000能量到达一号空间站,花光20000银河币补满能量后,再行驶5000到达基地。
算法设计要考虑边缘数据。例如本题目,可能存在无需补给就直接行驶到基地的情况,也能存在bi>s的情况。

正确代码:参考:18718 航行(深搜/暴力)
深度搜索,每走一步就判断能否走下一步

PS:距离和坐标的关系!


#include <iostream>
using namespace std;

//定义结构体,包含空间站坐标和银河币花销
struct node
{
    int xy;//空间站坐标
    int cost;//花销
}spa[250];//重命名为Spa[]

int N,L,M,S;
bool flag = false;//能否到达基地的标记

void dfs(int money,int energy,int pos,int num)//每一次的消费,补充的能量(常为M),当前站点坐标,当前站点(Spa索引)
{
    //出口(条件:不管有没有用完钱,只判断能否到终点)
    if(pos + energy >= L){ //初始能量+补充的能量能支撑到达基地
        flag = true;
        return;
    }
    //没到基地,进行深搜
    //到下一个空间站补给
    for(int i = num + 1 ;i <= N;i++){ //从下一个空间站开始搜索
        //判断能否走下一步
        //钱够在第i个站点消费 && 能量足够到达第i空间站(即能量 > 两空间站之间距离)
        //两空间站之间距离 = 第i个空间站坐标-上一个空间站坐标,记住是坐标!!求距离要坐标相减
        if(money >= spa[i].cost && energy >= spa[i].xy - pos){
            //花钱了,补充能量,然后继续搜索下一个空间站
            dfs(money - spa[i].cost, energy, spa[i].xy,num + 1);//到达下一个空间站,继续搜索
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin >> N >> L >> M >> S;
    //输入结构体
    for(int i = 1;i <= N;i++){
        //输入第i个站点的坐标和花销
        cin >> spa[i].xy >> spa[i].cost;
    }
    if(M >= L){ //初始能量足够直接到达终点
        flag = 1;
    }
    //进行深搜,从S,0,0开始(原点)
    dfs(S,M,0,0);
    if(flag){
        cout << "Yes";
    }
    else{
        cout << "No";
    }
    return 0;
}

尝试方法1(错误的!!!)
队列,所有空间站入队,在判断是否停靠
(无法AC,但是实在找不到哪里错了(太混乱),放弃这个思路了)

#include <iostream>
#include <queue>

using namespace std;

int main()
{
    ios::sync_with_stdio(false);
    int N,L,M,S;
    cin >> N >> L >> M >> S;
    int a,b;
    //构建队列
    queue<int> A;//坐标(路程)
    queue<int> B;//银河币
    //坐标和需花费的银河币入队
    for(int i = 0;i < N;i++){
        cin >> a >> b;
        A.push(a);
        B.push(b);
    }
    //L入队
     A.push(L);
     /*for(int i = 0;i < N + 1;i++){
        cout << A.front() << " ";
        A.pop();
    }*/
    //能量M足够行驶到基地
    if(M >= L){
        cout << "Yes" << endl;
        return 0;
    }
    //遍历队
    int t,x,d = A.front(),res = M;
    while(A.front() < L){//当A队列只剩L时即到达基地
        
        x = d;//上一个空间站到本次空间站的距离(上段路程)
        res = res - d;//到达当前空间站时剩余能量
        t = A.front();
        A.pop();
        d = A.front() - t;//当前空间站到下一个空间站的距离
        
        if(res < 0){ //上一站和本站的距离大于满额的能量,无法到达
            cout << "No" << endl;
            return 0;
        }
        else if(res - d <= 0){ //剩余能量不足以到达下一个空间站,因此需要在当前空间站停靠
            if(S <= 0 && A.front() != L){ //没钱了且下一站不是基地
            cout << "No" << endl;
            return 0;
            }
            S -= B.front();
            res = M;//充满能量
            B.pop();
        }
        else{ //剩余能量足够支撑到达下一个空间站,本次不停靠
            B.pop();
        }  
    }
    //遍历结束,飞船到基地
    cout << "Yes" << endl;

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值