1. 程式人生 > >1489 蜥蜴和地下室+bfs

1489 蜥蜴和地下室+bfs

題目連結:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1489
題目大意:輸入第一行包含3個整數 n, a, b
第二行輸入n只蜥蜴的生命值,你可以選擇編號為2~n的任意第i只蜥蜴進行火球術,對第i只蜥蜴造成a點傷害,對左右的蜥蜴造成b點傷害,當生命值<0時蜥蜴死亡(巨坑),但可以繼續攻擊,求殺死全部蜥蜴的最小攻擊次數。

在這裡插入圖片描述

n和hi的範圍都比較小,考慮dfs。
當是純dfs會爆,所以還要有策略的dfs。

因為這道題有點和poj那個熄滅燈泡有的像。必須找到一個狀態,再dfs。因為題目中說第1,n不能直接打。所以1,n只能通過打2,n-1消滅。然後從左到右打,消滅第i只有兩種方式。
一:打第i只,需要打(hi+a-1)/a下。
二:打第i+1只,需要打(hi+b-1)/b下。
但是這裡只考慮打打第i+1只,因為打第i-1只時,便是第一種打法。
開始考慮把第i只消滅,就消滅第i+1推導第n只。但是最後一隻要特殊考慮。因為a>b;直接打本身更快,然後提交有幾個樣例WA了。

後來發現考慮有點問題,因為上面說因為打第i-1只時,便是第一種打法。因為打第i-1只時只打了(h(i-1)+b-1)/b)可能是小於(hi+a-1)/a的,這樣打(h(i-1)+b-1)/b)~(hi+a-1)/a下第i-1只都會死亡,所以dfs打的次數。AC

#include<bits/stdc++.h>
using namespace std;

int s[20];
int min_s=0x7fffffff;
int n, a, b;

void dfs(int i, int ans)
{
    if(i==n)
    {
        min_s=min(min_s, ans);
        return;
    }
    if(s[i]<=0)
    {
        dfs(i+1, ans);
    }
    int m1=0;
    if(s[i]>0)//情況二
    {
        m1=(s[i]+b-1)/b;
        s[i]-=m1*b;
        s[i+1]-=m1*a;
        s[i+2]-=m1*b;
        dfs(i+1, ans+m1);
        s[i]+=m1*b;
        s[i+1]+=m1*a;
        s[i+2]+=m1*b;
    }
    int m2=(s[i+1]+a-1)/a;
    
    if(m2>m1) //(h(i-1)+b-1)/b小於(hi+a-1)/a
    {
        for(int j=m1+1;j<=m2;j++)
        {
            s[i]-=j*b;
            s[i+1]-=j*a;
            s[i+2]-=j*b;
            dfs(i+1, ans+j);
            s[i]+=j*b;
            s[i+1]+=j*a;
            s[i+2]+=j*b;
        }
    }

}

int main()
{
    scanf("%d%d%d",&n,&a,&b);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&s[i]);
        s[i]++;
    }
    int m1=(s[1]+b-1)/b;//消滅第1只
    s[1]=0;
    s[2]-=a*m1;
    s[3]-=b*m1;

    int m2=(s[n]+b-1)/b;//消滅第n只
    m2=max(0, m2);
    s[n]=0;

    if(n-1>=0)
        s[n-1]-=a*m2;
    if(n-2>=0)
        s[n-2]-=b*m2;

    dfs(2, m1+m2);

    cout<<min_s<<endl;

    return 0;
}