UPC 黑熊过河(基本状态转移)

从题目中看出,在1~n的范围之外还存在两个起始终末端点:0和n+1,而在2~n+1范围内的状态都是可以由i-1和i-2所转移得来,所以将其划分为一个部分,而0与1不能有这样的状态转移方式,所以是另一个单独解决的部分。

这个题没有必要担心存在那种跳回去又折回来的情况,因为在最优解中肯定是在起始端点那一侧向终末端点那一侧跳的,否则就是白白浪费体力。

除了n+1这个状态之外,所有状态都必须确认当前状态数值不得小于起跳所需能量数值,否则这个状态就是毫无意义的,因为在到达终点之前就损失了所有行动能力。

也就是会有如下的思路:

  1. 单独判断黑熊位于0和1的状态
  2. 利用递推解决黑熊位于2~n+1的状态
//#include
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define DETERMINATION main
#define lldin(a) scanf_s("%lld", &a)
#define println(a) printf("%lld\n", a)
#define reset(a, b) memset(a, b, sizeof(a))
const int INF = 0x3f3f3f3f;
using namespace std;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1000000007;
const int tool_const = 19991126;
const int tool_const2 = 2000;
inline ll lldcin()
{
    ll tmp = 0, si = 1;
    char c;
    c = getchar();
    while (c > '9' || c < '0')
    {
        if (c == '-')
            si = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        tmp = tmp * 10 + c - '0';
        c = getchar();
    }
    return si * tmp;
}
///Untersee Boot IXD2(1942)
/**Although there will be many obstructs ahead,
the desire for victory still fills you with determination..**/
/**Last Remote**/
ll a[65555],dp[65555],vis[65555];
int DETERMINATION()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    ll p, q;
    cin >> p >> q;
    ll n;
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    a[n + 1] = 0;//把n+1这个地方也看作一个石墩子
    dp[0] = p;
    if (dp[0] < q)//丧失行动能力
    {
        cout << "NO" << endl;
        return 0;
    }
    vis[0] = true;
    dp[1] = dp[0] - q + a[1];
    if (dp[1] >= q)//在这个点没有丧失行动能力,这个点才算是有效的
        vis[1] = true;
    for (int i = 2; i <= n+1; i++)
    {
        if (vis[i - 1] + vis[i - 2] == 0)//以任何方式都无法到达
        {
            cout << "NO" << endl;
            return 0;
        }
        else if (vis[i - 1] && !vis[i - 2])
            dp[i] = a[i] - q + dp[i - 1];
        else if (vis[i - 2] && !vis[i - 1])
            dp[i] = a[i] - q + dp[i - 2];
        else
            dp[i] = max(dp[i - 2] + a[i] - q, dp[i - 1] + a[i] - q);
        if (dp[i] - q >= 0)//在这个点没有丧失行动能力,这个点才算是有效的
            vis[i] = true;
    }
    cout << dp[n + 1] << endl;
    return 0;
}

 

你可能感兴趣的:(动态规划,动态规划题解)