把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

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;
}
posted @ 2018-08-06 08:35  Starlight_Glimmer  阅读(11)  评论(0编辑  收藏  举报  来源
浏览器标题切换
浏览器标题切换end