哈利喜欢玩角色扮演的电脑游戏《蜥蜴和地下室》。此时,他正在扮演一个魔术师。在最后一关,他必须和一排的弓箭手战斗。他唯一能消灭他们的办法是一个火球咒语。如果哈利用他的火球咒语攻击第i个弓箭手(他们从左到右标记),这个弓箭手会失去a点生命值。同时,这个咒语使与第i个弓箭手左右相邻的弓箭手(如果存在)分别失去b(1 ≤ b < a ≤ 10)点生命值。
因为两个端点的弓箭手(即标记为1和n的弓箭手)与你相隔较远,所以火球不能直接攻击他们。但是哈利能用他的火球攻击其他任何弓箭手。
每个弓箭手的生命值都已知。当一个弓箭手的生命值小于0时,这个弓箭手会死亡。请求出哈利杀死所有的敌人所需使用的最少的火球数。
如果弓箭手已经死亡,哈利仍旧可以将他的火球扔向这个弓箭手。
Input
第一行包含3个整数 n, a, b (3 ≤ n ≤ 10; 1 ≤ b < a ≤ 10),第二行包含n个整数——h1,h2,…,hn (1 ≤ hi ≤ 15), hi 是第i个弓箭手所拥有的生命力。
Output
以一行输出t——所需要的最少的火球数。
Input示例
3 2 1
2 2 2
Output示例
3
想了好久的一个DP题(好弱,,,),两端敌人是无法直接攻击到的,杀死他们的办法是唯一的,所以首先贪心处理两端的敌人,然后题目要求有点奇葩,每个人还得生命值小于0才死,所以在开始直接给每个人的生命值+1,然后当成生命值为0的时候死去做。
之后对处理完的敌人可以这样考虑,首先定义状态:
dp[i][j][k][l]表示对于第i个人,自己状态为k,前一个人状态为j,后一个人状态为l时所需发射最小火球术。
如果你对第i个人进行直接火球攻击,那么对i,j,k分别减去对应的值,得到子状态进行更新,然后如果j==0时,还应更新:
dp[i+1][k][l][num[i+2]]的值。
#include<bits/stdc++.h>
using namespace std;
#define D(x,t) x-a*t>0?x-t*a:0
#define ID(x,t) x-b*t>0?x-t*b:0
const int INF=0X7fffffff;
int dp[20][20][20][20]; //dp[i][i-1][i][i+1]:当对第i个敌人直接发射火球时可能的状态,i为第k-1的人,j为第k个人
int n,a,b;
int main()
{
while(cin>>n>>a>>b)
{
int num[25];
int sum_times=0;
memset(num,0,sizeof(num));
for(int i=0;i<n;i++)
{
scanf("%d",&num[i]);
num[i]++;
}
//先对数据进行处理
int times=ceil((double)num[0]/b);
sum_times+=times;
num[1]=D(num[1],times);
num[2]=ID(num[2],times);
times=ceil((double)num[n-1]/b);
sum_times+=times;
num[n-2]=D(num[n-2],times);
num[n-3]=ID(num[n-3],times);
num[0]=num[n-1]=0;
//初始化为无穷大
for(int i=0;i<20;i++)
for(int j=0;j<20;j++)
for(int k=0;k<20;k++)
for(int l=0;l<20;l++)
dp[i][j][k][l]=INF;
dp[1][0][num[1]][num[2]]=0;
for(int i=1;i<n-1;i++)
for(int l=num[i+1];l>=0;l--)
for(int k=num[i];k>=0;k--)
for(int j=num[i-1];j>=0;j--)
{
if(dp[i][j][k][l]!=INF)
{
int z=0;
while(1)
{
// cout<<2<<endl;
int aa=ID(j,z);
int bb=D(k,z);
int cc=ID(l,z);
dp[i][aa][bb][cc]=min(dp[i][j][k][l]+z,dp[i][aa][bb][cc]);
if(!aa)
dp[i+1][bb][cc][num[i+2]]=min(dp[i][j][k][l]+z,dp[i+1][bb][cc][num[i+2]]);
z++;
if(!bb&&!aa&&!cc) break;
}
}
}
cout<<dp[n-1][0][0][0]+sum_times<<endl;
}
}