Aizu 2155 Magic Slayer 背包DP

这是上上次对抗赛的题目了

其实现在发现整个代码从头到尾,都是用了背包,怪我们背包没深入学好。

比赛的时候,聪哥提出的一种思路是,预处理一下,背包出 ALL攻击 和 single攻击的 血量对应的最小花费,其实这些都没什么问题。。。主要是后面的问题,后面为了找到如何使用ALL攻击是最好的,我们是这样处理的,对怪物血量 升序排序,然后枚举,从哪个点开始,该点前面的怪物都用ALL杀死,后面的怪物都用single杀死,因为血高的放在后面多承受几次ALL攻击应该是最优的,这样看起来好像是对的。。也过了样例,就是WA了。。。。其实WA的很明显,我们居然三个人都没想到,刚刚重新敲这道题才发现这个策略大错特错了,我们这样枚举,很明显,没有计算,用了ALL攻击,但是没有杀死怪物的情况,也许这些就是最优解。。我们的策略,要么就不用ALL攻击,用了ALL攻击就一定要把怪物杀死。。。肯定有问题啊。

后来还是参考的别人的比较好的思路,前面的处理是一样的,不过换了一下,背包出 两种攻击 的 花费 对应的 最大攻击,即 下标是 花费,值是攻击力,这样便于后面的处理。

背包完之后,从0开始往上枚举 出 使用ALL的花费情况,然后就得到ALL的攻击总量,再遍历一遍怪物,就可以得到剩余血量用single攻击的花费,全部加起来就是可能的结果,全部枚举完就能求出最优解

刚刚还和聪哥讨论了好久,为什么枚举ALL花费情况就可以得到所有合理的ALL攻击组合,这其实就是利用了背包的特性,即,我给你一个上限,就能帮我求出这个上限中的最优组合,就是利用了背包的特性。。。所以我为什么说这整个题目就是一个背包题,全部都在利用背包的特性。。怪我没有对背包理解透彻,这种隐藏的可以枚举花费,通过背包得到组合情况没有想到。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 110010
using namespace std;
int hp[110];

struct weapon{
    int c,p;
}all[110],sig[110];
int dp[2][N];
int all_num,sig_num;
int m,n;
void init()
{
    all_num=sig_num=0;
}
void proc()
{
    memset(dp,0,sizeof dp);
    for (int i=0;i<all_num;i++){
       for (int j=all[i].c;j<N;j++){
         dp[0][j]=max(dp[0][j],dp[0][j-all[i].c]+all[i].p);
       }
    }
    for (int i=0;i<sig_num;i++){
        for (int j=sig[i].c;j<N;j++){
            dp[1][j]=max(dp[1][j],dp[1][j-sig[i].c]+sig[i].p);
        }
    }
}
int bs(int val)
{
    int l=0,r=N-1,mid;
    while (l<r)
    {
        mid=(l+r)>>1;
        if (dp[1][mid]<val) l=mid+1;
        else  r=mid;
    }
    return l;

}
int main()
{
    char ch[20],cc[10];
    int a,b;
    while (scanf("%d",&n)){
        if (!n) break;
        init();
        for (int i=0;i<n;i++) scanf("%d",&hp[i]);
        scanf("%d",&m);
        bool flag=false;
        for (int i=0;i<m;i++){
            scanf("%s %d %s %d",ch,&a,cc,&b);
           // cout<<a<<" "<<b<<endl;
            if (cc[0]=='A') all[all_num++]=(weapon){a,b};
            if (cc[0]=='S') sig[sig_num++]=(weapon){a,b};
            if (a==0 && b>0) flag=1;
        }
        if (flag) {puts("0");continue;}
        proc();
        int ans=N*99;
        for (int i=0;i<ans;i++){
            int temp=i;
            for (int j=0;j<n;j++){
                temp+=bs(hp[j]-dp[0][i]);
            }
            ans=min(ans,temp);
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2014-05-26 23:12  KRisen  阅读(192)  评论(0编辑  收藏  举报