zoukankan      html  css  js  c++  java
  • 动态规划背包问题--做题小总结

    题目来源:2017“百度之星”晋级赛 1003

    Time Limit: 2000/1000 MS (Java/Others)

    Memory Limit: 32768/32768 K (Java/Others)

    Problem description:

    度度熊为了拯救可爱的公主,于是与邪恶大魔王战斗起来。

    邪恶大魔王的麾下有n个怪兽,每个怪兽有a[i]的生命值,以及b[i]的防御力。

    度度熊一共拥有m种攻击方式,第i种攻击方式,需要消耗k[i]的晶石,造成p[i]点伤害。

    当然,如果度度熊使用第i个技能打在第j个怪兽上面的话,会使得第j个怪兽的生命值减少p[i]-b[j],当然如果伤害小于防御,那么攻击就不会奏效。

    如果怪兽的生命值降为0或以下,那么怪兽就会被消灭。

    当然每个技能都可以使用无限次。

    请问度度熊最少携带多少晶石,就可以消灭所有的怪兽。

    Input:

    本题包含若干组测试数据。

    第一行两个整数n,m,表示有n个怪兽,m种技能。

    接下来n行,每行两个整数,a[i],b[i],分别表示怪兽的生命值和防御力。

    再接下来m行,每行两个整数k[i]和p[i],分别表示技能的消耗晶石数目和技能的伤害值。

    数据范围:

    1<=n<=100000

    1<=m<=1000

    1<=a[i]<=1000

    0<=b[i]<=10

    0<=k[i]<=100000

    0<=p[i]<=1000

    Output:

    对于每组测试数据,输出最小的晶石消耗数量,如果不能击败所有的怪兽,输出-1.

    解析:

        这是一道动态规划的题目,其思想就是比较经典的背包问题的思想。首先我们考虑单独的一个怪兽i,问打败该怪兽最少的花费是多少。

    对于技能序列(k,p),进行动态规划。令数组F[i][j]代表的含义为:当1到i技能可选时,打败生命值为j的怪兽所需的最小花费。

    对于打败所有怪兽的花费则是打败每个怪兽的最小花费的叠加。

    这里需要统计每个怪兽被打败的最小花费,当然不能对每一个怪兽都进行一次动态规划。采取的办法是预先处理出一个cnt[i][j]数组,记录对于防御值为i, 生命值为j的怪兽所需的最小花费。我们发现防御值B_j的范围比较小,0~10,这是一个切入点。我们可以枚举B,并对应每个防御值,进行动态规划。

    具体的过程分为三种情况:

    1)f[i][j] = min(经此攻击之后的f’[i][j]+此攻击的花费,不采用此攻击的花费),因而限制条件是经历此攻击之后的f’[i][j]是存在的:j-p[i]+B>0,当然此攻击是有效的:p[i]>B。

    if(p[i] > B && (j-p[i]+B) > 0)

           f[i][j] = _min(f[i][j-p[i]+B]+k[i],f[i-1][j]);

    2)如果该次攻击就已经消灭了怪兽,则直接将本次攻击的花费,与不采用此攻击的花费进行对比。

    else if(p[i] > B && (j-p[i]+B) <= 0)

           f[i][j] = _min(k[i],f[i-1][j]);

    3)如果该攻击是无效的,则不采取该攻击,f[i][j] = f[i-1][j].

    else if(p[i] <= B)

           f[i][j] =  f[i-1][j];

      

       整个算法的思路就是这样。F[i][j]这个二维数组对于不同的B可以重复利用,当B更新时,对F数组进行初始化即可。每次动态规划完毕,对cnt[][]进行赋值。

    Code:

    #include <iostream>

    #include <cstdio>

    #include <algorithm>

    #include <cmath>

    #include <vector>

    #include <cstring>

    #include <queue>

    #include <ctime>

    #include <set>

    using namespace std;

    typedef long long ll;

    typedef long double ld;

    typedef pair<int,int> pii;

    const ll INF = 10e16;

    const int maxN = 100010;

    const int maxM = 1010;

    const int maxK = 16;

    int a[maxN];

    int b[maxN];

    int k[maxN];

    int p[maxN];

     

    ll f[maxM][maxM];

    ll cnt[12][maxM];

    ll _min(ll a,ll b)

    {

        if(a>b)

            return b;

        else

            return a;

    }

    void _clr(int m)   //清空

    {

        for(int i=0;i<=m;i++)

            for(int j=0;j<maxM;j++)

            {

                if(i==0 && j==0)

                    f[i][j] = 0;

                else

                    f[i][j] = INF;

            }

    }

    int main()

    {

        int n,m;

        while(scanf("%d%d",&n,&m) !=EOF)

        {

            for(int i=1;i<=n;i++)

            {

                scanf("%d%d",&a[i],&b[i]);   

            }           

            int maxp = 0;                    //找到最大攻击力

            for(int i=1;i<=m;i++)

            {

                scanf("%d%d",&k[i],&p[i]);

                maxp = max(maxp,p[i]);

            }

            for(int B=0;B<=10;B++)

            {

                _clr(m);

                for(int i=1;i<=m;i++)

                {

                    for(int j=1;j<maxM;j++)

                    {

                        if(p[i] > B && (j-p[i]+B) > 0)

                            f[i][j] = _min(f[i][j-p[i]+B]+k[i],f[i-1][j]);

                        else if(p[i] > B && (j-p[i]+B) <= 0)

                            f[i][j] = _min(k[i],f[i-1][j]);

                        else if(p[i] <= B)

                            f[i][j] =  f[i-1][j];

                    }

                }

                for(int j=1;j<maxM;j++)

                {

                    cnt[B][j] = f[m][j];

                }

            }   

            ll ans = 0;

            int flag = 0;

            for(int i=1;i<=n;i++)

            {

                int x = a[i];

                int y = b[i];

                if( y>= maxp)         //有一个怪兽 的防御值 大于等于最大攻击值

                {

                    flag = 1;

                    break;

                }

                ans += cnt[y][x];       

            }   

            if(!flag)

                printf("%lld ",ans);   

            else

                puts("-1");                   

        }

        return 0;

    }

  • 相关阅读:
    JS权威指南读书笔记(二)
    JS权威指南读书笔记(一)
    NodeList和HTMLCollection区别
    2016年前端技术展望
    Label标签for属性
    JavaScript Array vs new Array区别
    禁止滚动事件方法
    shim和polyfill 区别解释
    Html5知识精粹纪录
    前端url 相关设置获取总结
  • 原文地址:https://www.cnblogs.com/lavender-jlw/p/7399524.html
Copyright © 2011-2022 走看看