CodeForces - 6D Lizards and Basements 2【dfs】
题意简述:
你是火系法师,对面有一排敌人,每个敌人都有HP,你要向他们扔火球,扔 i时,i的HP减少a,同时i+1和i -1的HP减少b。法师只能攻击到2号到n-1号。如果一个人已经死了你还可以继续攻击它。问你至少要扔多少个火球才能杀死所有敌人,并依次输出每个火球的攻击目标。
注意:如果一个人已经死了你还可以继续攻击它。 之前没有注意到这一点,然后觉得好复杂,还脑补出了什么死了之后自动补位什么的qwq
分析
很裸的一个搜索
每一个位置的攻击次数是从0枚举到把相邻3个分别打死所需要的次数取max(这里用总HP除以了之后加个1,因为除法下取整,可能会多枚举一个,但对统计最小答案没有影响)
注意到第1个不能直接攻击,且对于每一个位置,最左边的那个必须在这里打死,不然后面就不能再打死了。
存答案时要判断一下第n个人有没有被打死,因为不能打他,所以如果它没死就不能存答案。
然后有人说直接暴搜可以过
然而亲测不加那个剪枝
if(sum>=ansn) return ;
在第43个点会T(可能是我实现不够好吧qwq)
但是这种显而易见的剪枝还是应该随手加上的,毕竟也不麻烦而且对正确性没有任何影响
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define MAXN 20
int h[MAXN],n,a,b,ansn=10000000;
vector<int> tmp;
vector<int> ans;
void dfs(int i,int sum)
{
if(sum>=ansn) return ;
if(i==n)//不能打第n个
{
if(h[i]<0&&sum<ansn)
{
ansn=sum;
ans=tmp;//存答案
}
return ;
}
for(int j=0;j<=max(h[i-1]/b+1,max(h[i]/a+1,h[i+1]/b+1));j++)
{
if(h[i-1]<b*j)//最左边的必须打死,不然他在后面就不能被打死
{
h[i-1]-=b*j;
h[i+1]-=b*j;
h[i]-=a*j;
for(int k=1;k<=j;k++)
tmp.push_back(i);
dfs(i+1,sum+j);
h[i-1]+=b*j;
h[i+1]+=b*j;
h[i]+=a*j;
for(int k=1;k<=j;k++)
tmp.pop_back();
}
}
}
int main()
{
scanf("%d %d %d",&n,&a,&b);
for(int i=1;i<=n;i++)
scanf("%d",&h[i]);
dfs(2,0);
printf("%d\n",ansn);
for(int i=0;i<ans.size();i++)
printf("%d ",ans[i]);
return 0;
}
转载请注明出处,有疑问欢迎探讨
博主邮箱 2775182058@qq.com