Luogu1941 飞扬的小鸟

本文深入探讨了一种基于完全背包的动态规划算法,通过具体的游戏模拟问题实例,详细阐述了算法的设计思路与实现细节,包括状态转移方程的推导、代码实现技巧以及注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这题的 dp 还是比较显然的

听说是个完全背包,大概转移是差不多的
就从当前层顺着枚举 j 往大去更新同层的就好了

其实这样每次往高处转移的就是下面的前缀最小值

值得注意的是题意要模拟的是游戏
所以显然不能先掉下去在在同一步中往上飞

所以转移顺序是不能乱的

就是先转移往上飞的在转移往下掉的

好像多开一维也行,不过没有必要了


 代码:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cstdio>
#include <cmath>
using namespace std;

const int MAX_N = 10005, MAX_M = 1005;

int n, m, k, max_dst;
int x[MAX_N], y[MAX_N], pos[MAX_N], pre_sum[MAX_N];
int bot[MAX_N], top[MAX_N], f[MAX_N][MAX_M];
bool has_stk[MAX_N];

int main() {
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 1; i <= n; ++i) scanf("%d%d", &x[i], &y[i]);
    for (int i = 1; i <= k; ++i) {
        scanf("%d", &pos[i]);
        scanf("%d%d", &bot[pos[i]], &top[pos[i]]);
        has_stk[pos[i]] = true;
    }
    for (int i = 1; i < n; ++i) pre_sum[i] = pre_sum[i - 1] + has_stk[i];
    memset(f, 0x3f, sizeof(f));
    for (int i = 1; i <= m; ++i) f[0][i] = 0;
    for (int i = 1; i <= n; ++i) {
        for (int j = x[i] + 1; j <= m; ++j) {
            max_dst = (f[i][j] < 0x3f3f3f3f) ? i : max_dst;
            f[i][j] = min(f[i][j], min(f[i - 1][j - x[i]], f[i][j - x[i]]) + 1);
        }
        for (int j = m - x[i]; j <= m; ++j) {
            max_dst = (f[i][j] < 0x3f3f3f3f) ? i : max_dst;
            f[i][m] = min(f[i][m], min(f[i - 1][j], f[i][j]) + 1);
        }
        for (int j = 1; j <= m - y[i]; ++j) {
            max_dst = (f[i][j] < 0x3f3f3f3f) ? i : max_dst;
            f[i][j] = min(f[i][j], f[i - 1][j + y[i]]);
        }
        if (has_stk[i]) {
            for (int j = 1; j <= bot[i]; ++j) f[i][j] = 0x3f3f3f3f;
            for (int j = top[i]; j <= m; ++j) f[i][j] = 0x3f3f3f3f;
        }
    }
    register int min_res = 0x3f3f3f3f;
    if (!has_stk[n]) {
        for (int i = 1; i <= m; ++i) if (f[n][i] < 0x3f3f3f3f) {
            max_dst = n;
            min_res = min(min_res, f[n][i]);
        }
    } else {
        for (int i = bot[n] + 1; i < top[n]; ++i) if (f[n][i] < 0x3f3f3f3f) {
            max_dst = n;
            min_res = min(min_res, f[n][i]);
        }
    }
    if (max_dst == n) {
        puts("1");
        printf("%d", min_res);
    } else {
        printf("0\n%d", pre_sum[max_dst] - has_stk[max_dst]);
    }
    return 0;
}

  

转载于:https://www.cnblogs.com/xcysblog/p/9908539.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值