CSP历年复赛题-P1095 [NOIP2007 普及组] 守望者的逃离

原题链接:https://www.luogu.com.cn/problem/P1095

题意解读:在有限的时间内,通过跑步或者闪烁两种方式,能跑出的最远距离是多少,以及是否能跑出出口。

解题思路:

1、贪心法

每一秒钟,都有两种选择:跑步(17米)、闪烁(60米,前提是蓝够10点,否则等待1s恢复4点蓝)

经过计算,恢复足够的蓝到闪烁需要3.5s,而3.5s跑步可以跑出59.5

因此,在时间充分的情况下,闪烁以及等待回蓝是最佳方案,但是在最后的几秒,跑步才是更佳!

所以,可以枚举每一秒,跑步、闪烁两种方式同步进行,计算各自前进的距离,下一秒跑步的距离要以之前两种方案跑出最远的距离为基准(闪烁跑得远就用闪烁,否则就跑步)

100分代码:

#include <bits/stdc++.h>
using namespace std;

int m, s, t;
int dist1; //跑步的距离
int dist2; //闪烁的距离

int main()
{
    cin >> m >> s >> t;
    for(int i = 1; i <= t; i++)
    {
        dist1 += 17; //跑步方式
        if(m >= 10) //闪烁方式
        { 
            dist2 += 60;
            m -= 10;
        }
        else
        {
            m += 4;
        }
        dist1 = max(dist1, dist2); //如果这一秒闪烁更远,跑步方式就改成闪烁

        if(dist1 >= s)
        {
            cout << "Yes\n" << i;
            return 0;
        } 
    }
    cout << "No\n" << dist1;
    return 0;
}

2、动态规划

状态表示:f[i]表示经过i秒能跑出的最大距离

状态转移:

  如果是闪烁:

    蓝够:f[i] = f[i-1] + 60,蓝减10

    蓝不够:f[i] = f[i-1],蓝加4

  如果是跑步:

    f[i] = f[i - 1] + 17

可以第一轮枚举时间使用闪烁跑一遍,再枚举一遍时间用跑步补充,比较两者谁更远

  f[i] = max(f[i],f[i-1] + 17)

初始化:f[0] = 0

结果:第一个f[i] > s,如果没有最远距离就是f[t]

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 300005;
int m, s, t;
int f[N]; //f[i]为前i秒最多跑出的距离

int main()
{
    cin >> m >> s >> t;
    for(int i = 1; i <= t; i++)
    {
        if(m >= 10) f[i] = f[i-1] + 60, m -= 10;
        else f[i] = f[i-1], m += 4;
    }
    for(int i = 1; i <= t; i++)
    {
        f[i] = max(f[i], f[i-1] + 17);
    }
    for(int i = 1; i <= t; i++)
    {
        if(f[i] >= s)
        {
            cout << "Yes\n" << i;
            return 0;
        }
    }
    cout << "No\n" << f[t];
    return 0;
}

 

posted @ 2024-05-26 18:16  五月江城  阅读(42)  评论(0编辑  收藏  举报