[DP] [贪心] [Vijos P1417] 魔法塔防 (mtower)

本文解析了一款名为“魔法塔防”的一维塔防游戏的最优策略算法。游戏涉及放置不同属性的魔法师来最大化敌人损失的生命值。文章提供了一个贪心优化的动态规划解决方案,并附带源代码。

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

题目描述 Description

塔防游戏(Tower Defence)是dd_engi非常喜爱的一类休闲游戏。在这类游戏中,玩家需要在地图上摆放各种防御单位,打击并阻止试图跨越地图的敌对单位。一般而言,敌对单位不会攻击防御单位,但若敌对单位未被防御单位消灭且成功跨越地图,玩家的生命数会减少。
dd_engi设计出了一种一维的塔防游戏,并将其命名为“魔法塔防”,规则如下:
游戏的地图是一行NNN个连续的魔法塔,其中行的一端是入口,另一端是出口,怪兽会从地图的一端向另一端移动。初始时,怪兽通过每个魔法塔的时间是TTT秒。玩家可以在这NNN个魔法塔中放置魔法师以对经过的怪兽造成伤害,每个魔法塔中最多放置一个魔法师,且放置好的魔法师不能改变位置。
共有三种不同属性的魔法师,分别是红色魔法师、蓝色魔法师和绿色魔法师,作用分别是攻击、减速以及下毒。当怪兽经过一个红色魔法师所在的魔法塔时,每秒钟生命值会减少RRR点;当怪兽从一个蓝色魔法师所在的魔法塔走出之后,通过每个魔法塔的时间延长BBB秒;当怪兽从一个绿色魔法师所在的魔法塔走出之后,每秒钟会因中毒失去GGG点生命值。蓝色魔法师的减速效果和绿色魔法师的下毒效果是可以累加的。也就是说,怪兽通过nnn个蓝色魔法师所在的魔法塔之后,它通过每个魔法塔的时间会变成T+BT+BT+B×nnn秒;怪兽通过nnn个绿色魔法师所在的魔法塔之后,它每秒钟会因中毒失去GGG×nnn点生命值。
现在,你的任务是,在这NNN个魔法塔里放置各种类型的魔法师,使通过的怪兽失去的生命值最大。输出这个最大值。

输入 Input

一行,五个空格隔开的整数 N、R、G、B、TN、R、G、B、TNRGBT

输出 Output

只需输出一行一个整数,即通过的怪兽失去的最大的生命值。

样例输入 Sample Input

5 4 3 2 1

样例输出 Sample Output

82

限制 Limits

数据范围
20%20\%20%的数据满足 N≤12N≤12N12
50%50\%50%的数据满足 N≤100N≤100N100
100%100\%100%的数据满足1≤N≤1024;0≤R,G,B≤65536;0≤T≤31≤N≤1024; 0 ≤ R, G, B ≤65536; 0 ≤ T ≤ 31N1024;0R,G,B65536;0T3
Time Limit : 1s1s1s & Memory Limit : 128MB128MB128MB

看题,还是没思路
要维护三个状态的话,n3n^3n3继续超时
要维护两个的话,维护哪两个?
随便两个?肯定不行,准确性呢?
于是爆零…
首先做这道题得会玩塔防游戏(据说我只玩的PvZ是塔防?)
蓝法师(就是冰法师)和绿法师(毒法师)是加Buff的(自带延长效果,类比寒冰射手,只是僵尸再也不会回原来状态了),绝对要放到前面(为啥?孩子不要沉迷于学习…),红法师(火法师)放在最后(gank掉剩下的血)。
ang?这不是贪心吗…
贪心优化的DP…
既然是要冰法师和毒法师放前面,维护的两个状态就是这两个,火法师做差求出
代码应该还很好懂吧…

#include <cstdio>
#define MAXN 1025
using namespace std;

long long dp[MAXN][MAXN];
long long ans;
long long n,r,g,b,t;

long long mymax(long long a,long long b)
{
    return a>b?a:b;
}

int main()
{
    scanf("%lld %lld %lld %lld %lld",&n,&r,&g,&b,&t);
    for (int i=0;i<=n;i++) //i为总共放置蓝法师塔数
        for (int j=0;j<=n-i;j++) //j为总共放置绿法师塔数
        {
            if (i) //你得先有蓝法师
                dp[i][j]=mymax(dp[i][j],dp[i-1][j]+g*j*(t+b*(i-1))); //只有走出塔才生效,i或j需要减1
            if (j) //同理
                dp[i][j]=mymax(dp[i][j],dp[i][j-1]+g*(j-1)*(t+b*i));
            ans=mymax(ans,dp[i][j]+(n-i-j)*(g*j+r)*(t+i*b));//小小的运用了一下结合律
        }
    printf("%lld\n",ans);
    return 0;
}

学好OI,你得先打好游戏…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值