度度熊与邪恶大魔王

HDU 传送门
这是一道变形的完全背包。
我们用dp[i][j]表示打倒血量为i防御力为j的恶魔的最小花费。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
LL n,m;
LL a[100009],b[100009];
LL k[1009],p[1009];
LL ans,dp[3001][20];//dp[i][j]表示打倒生命值为 i ,防御值为 j 的恶魔的最小花费 
void work()
{
    ans=0;
    LL mp=0,mb=0,ma=0;//最大攻击值,最大防御值,最大生命值 
    for(int i=1;i<=n;i++) {scanf("%lld%lld",&a[i],&b[i]);mb=max(mb,b[i]);ma=max(ma,a[i]);}
    for(int i=1;i<=m;i++) {scanf("%lld%lld",&k[i],&p[i]);mp=max(mp,p[i]);}
    if(mp<=mb){printf("-1
");return;}

    memset(dp,0,sizeof(dp));
    for(int i=0;i<=mb;i++)//防御值 
    {
        for(int j=1;j<=ma;j++)//生命值 
        {
            dp[j][i]=INF;
            for(int o=1;o<=m;o++)
            {
                LL down=p[o]-i;//伤害值 
                if(down<=0) continue;
                else if(down>=j) dp[j][i]=min(dp[j][i],k[o]);//一次性打倒 
                else dp[j][i]=min(dp[j][i],dp[j-down][i]+k[o]);//打下一部分血量 
            }
        }
    } 

    for(int i=1;i<=n;i++)
     ans+=dp[a[i]][b[i]]; 
    printf("%lld
",ans);
}
int main()
{
    while(scanf("%lld%lld",&n,&m)!=EOF) work();
    return 0;
}
原文地址:https://www.cnblogs.com/dfsac/p/7587815.html