1489 蜥蜴和地下室
Posted joeylee97
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了1489 蜥蜴和地下室相关的知识,希望对你有一定的参考价值。
收藏
关注
哈利喜欢玩角色扮演的电脑游戏《蜥蜴和地下室》。此时,他正在扮演一个魔术师。在最后一关,他必须和一排的弓箭手战斗。他唯一能消灭他们的办法是一个火球咒语。如果哈利用他的火球咒语攻击第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
#include<iostream> #include<vector> #include<algorithm> #include<cstdio> using namespace std; typedef long long LL; /* 哈利喜欢玩角色扮演的电脑游戏《蜥蜴和地下室》。此时,他正在扮演一个魔术师。在最后一关,他必须和一排的弓箭手战斗。他唯一能消灭他们的办法是一个火球咒语。如果哈利用他的火球咒语攻击第i个弓箭手(他们从左到右标记),这个弓箭手会失去a点生命值。同时,这个咒语使与第i个弓箭手左右相邻的弓箭手(如果存在)分别失去b(1 ≤ b < a ≤ 10)点生命值。 因为两个端点的弓箭手(即标记为1和n的弓箭手)与你相隔较远,所以火球不能直接攻击他们。但是哈利能用他的火球攻击其他任何弓箭手。 每个弓箭手的生命值都已知。当一个弓箭手的生命值小于0时,这个弓箭手会死亡。请求出哈利杀死所有的敌人所需使用的最少的火球数。 如果弓箭手已经死亡,哈利仍旧可以将他的火球扔向这个弓箭手。 bfs搜索,node{step,状态_int[15]}状态不好记录 用dfs搜索,搜完一个状态后取消标记. */ bool f = false; int n,a,b,step=0,ans = 99999,h[15]; inline bool check() { for(int i=0;i<n;i++) if(h[i]>=0) return false; return true; } void DFS(int pos) { if(check()) { ans = min(ans,step); return ; } for(int i=1;i<n-1;i++) { if(h[i]<0&&h[i+1]<0&&h[i-1]<0) continue; h[pos] -= a,h[pos-1]-=b,h[pos+1]-=b; step++; DFS(i); h[pos] += a,h[pos-1]+=b,h[pos+1]+=b; step--; } } int main() { cin>>n>>a>>b; for(int i=0;i<n;i++) cin>>h[i]; if(h[0]%b<b) { step+=h[0]/b+1; h[1]-=h[0]/b*a+a; h[2]-=h[0]/b*b+b; h[0]-=h[0]/b*b+b; } else { step+=h[0]/b; h[1]-=h[0]/b*a+a; h[2]-=h[0]/b*b; h[0]-=h[0]/b*b; } if(check()) { cout<<step<<endl; return 0; } if(h[n-1]%b<b) { step+=h[n-1]/b+1; h[n-2] -= h[n-1]/b*a+a; h[n-3] -= h[n-1]/b*b +b; h[n-1] -= h[n-1]/b*b +b; } else { step+=h[n-1]/b; h[n-2] -= h[n-1]/b*a+a; h[n-3] -= h[n-1]/b*b; h[n-1] -= h[n-1]/b*b; } if(check()) { cout<<step<<endl; return 0; } for(int i=1;i<n-1;i++) { if(h[i]<0&&h[i+1]<0&&h[i-1]<0) continue; DFS(i); } cout<<ans<<endl; return 0; }
以上是超时的代码,递归次数太多,下面是网上的解法,在一个特定点求出其能发火球的上下界然后在其中遍历,这样能减少重复:因为在方法一中前后顺序不同需要不同遍历浪费时间。
#include <iostream> using namespace std; const int INF = 0x3f3f3f3f; const int MAXN = 11; int res = 0; // 打爆首尾需要的次数 int res_2 = INF;// 打爆中间的需要的最少次数 int n, a, b; int H[MAXN]; // 生命值 // 暴力深搜 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(int argc, const char * argv[]) { // freopen("/Users/zyj/Desktop/input.txt", "r", stdin); cin >> n >> a >> b; for (int i = 1; i <= n; i++) { cin >> 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; } std::cout << res + res_2 << ‘\n‘; return 0; }
以上是关于1489 蜥蜴和地下室的主要内容,如果未能解决你的问题,请参考以下文章