1489 蜥蜴和地下室 51NOD

来源:互联网 发布:lolita淘宝 编辑:程序博客网 时间:2024/04/29 16:40

哈利喜欢玩角色扮演的电脑游戏《蜥蜴和地下室》。此时,他正在扮演一个魔术师。在最后一关,他必须和一排的弓箭手战斗。他唯一能消灭他们的办法是一个火球咒语。如果哈利用他的火球咒语攻击第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:0const 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;   }}
0 0
原创粉丝点击