zoukankan      html  css  js  c++  java
  • 1489 蜥蜴和地下室

    题目来源: CodeForces
    基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题
     收藏
     关注

    哈利喜欢玩角色扮演的电脑游戏《蜥蜴和地下室》。此时,他正在扮演一个魔术师。在最后一关,他必须和一排的弓箭手战斗。他唯一能消灭他们的办法是一个火球咒语。如果哈利用他的火球咒语攻击第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 << '
    ';
        return 0;
    }
  • 相关阅读:
    dll-IL-metadata-反射
    Linux(Ubuntu)下安装Angular2
    在nodejs中使用input file批量上传文件的方法
    jq动态添加的元素触发绑定事件无效
    简单的在线计算器
    不同方法实现按钮背景图片的变换
    unity特殊文件夹
    《暗黑战神》随堂笔记
    《打砖块》教程知识梳理
    unity零散小知识
  • 原文地址:https://www.cnblogs.com/joeylee97/p/6323653.html
Copyright © 2011-2022 走看看