哈利喜欢玩角色扮演的电脑游戏《蜥蜴和地下室》。此时,他正在扮演一个魔术师。在最后一关,他必须和一排的弓箭手战斗。他唯一能消灭他们的办法是一个火球咒语。如果哈利用他的火球咒语攻击第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
System Message
(题目提供者)
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1489
思路:首先要打死两头的弓箭手,然后DFS搜素打死中间弓箭手的最优。对于第N个弓箭手,要想继续搜素N+1个,就必须使
N-1个小于0,不需要顾及N,所以递归搜素满足N-1小于0的条件即可。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int res = 0; // 打爆首尾需要的次数
int res_2 = INF;// 打爆中间的需要的最少次数
int n, a, b;
int H[11]; // 生命值
void dfs(int N, int ans)
{
// 当到达第n个人时,更新最少的爆破次数,并返回
if (N == n)
{
res_2 = res_2 > ans ? ans : res_2;
return ;
}
// 每次向后搜索都要保证第N-1个为负数
if (H[N - 1] < 0)
{
dfs(N + 1, ans);
}
int times = 0;
// 必须在第N位置爆times次才能保证第N-1个为负数
if (H[N - 1] >= 0)
{
times = H[N - 1] / b + 1;
H[N - 1] -= b * times;
H[N] -= a * times;
H[N + 1] -= b * times;
dfs(N + 1, ans + times);
H[N - 1] += b * times;
H[N] += a * times;
H[N + 1] += b * times;
}
// 只要爆times~times_次都能保证第N-1个为负数
int times_ = H[N] / a + 1;
if (H[N] >= 0 && times_ > times)
{
for (int i = times + 1; i <= times_; i++)
{
H[N - 1] -= b * i;
H[N] -= a * i;
H[N + 1] -= b * i;
dfs(N + 1, ans + i);
H[N - 1] += b * i;
H[N] += a * i;
H[N + 1] += b * i;
}
}
return ;
}
int main()
{
scanf("%d %d %d", &n, &a, &b);
for (int i = 1; i <= n; i++)
{
scanf("%d", &H[i]);
}
// 打爆第1个
int times = H[1] / b + 1;
res += times;
H[1] -= b * times;
H[2] -= a * times;
H[3] -= b * times;
// 打爆第n个
if (H[n] >= 0)
{
times = H[n] / b + 1;
res += times;
H[n] -= b * times;
H[n - 1] -= a * times;
H[n - 2] -= b * times;
}
dfs(2, 0);
// 保证res_2是有效次数
if (res_2 == INF)
{
res_2 = 0;
}
printf("%d\n", res + res_2);
return 0;
}