白河夜船,日暮途远

Codeforces名字:LittleFall . 我为小萌上红名!

dp训练第21题 vijos 1198 最佳课题选择 背包dp-泛化物品

背包容量为v(200),物品数为n(20),每个物品给定两个参数Ai(100),Bi(5),表示选择k的体积的该物品需要花费Ai*k^Bi,k为任意正整数.现在要求装满背包,求最小花费.

注意到Bi最大只有5,所以物品最多只有5件了.
每个物品枚举体积1到200,最大值不到1e14,做一下分组背包,这里实际使用的是泛化物品的思想.

把物品从20件变成5件居然wa了??换成20件就过了??

对拍了一下,明白了怎么回事:
本题中bi相同时ai较大的并不一定无用,因为是指数运算,它可以额外选择物品来减少指数增长.
这个事例告诉我们,优化之前一定要确定能否优化!
而且,出现bug时可以还原基础的状态进行调试.

AC代码

/* LittleFall : Hello! */
#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int read();
inline void write(int x);
const int M = 100016;
ll A[50],B[50]; //save[i]->Ai i->Bi
ll dp[M];
ll power(ll a, ll b)
{
    ll ans = 1;
    while(b)
    {
        if(b & 1)   ans = ans * a;
        a = a * a;
        b >>= 1;
    }
    return ans;
}
int main(void)
{
    #ifdef _LITTLEFALL_
    freopen("in.txt","r",stdin);
    #endif
    //std::cin.sync_with_stdio(false); 

    int v=read(),n=read();
    for(int i=1;i<=n;i++)
        A[i]=read(),B[i]=read();
    for(int i=1;i<=v;i++)
        dp[i]=LLONG_MAX;
    for(int i=1;i<=n;i++)
        for(int j=v;j;j--)
            for(int k=1;k<=j;k++)
                if(dp[j-k]!=LLONG_MAX)
                    dp[j]=min(dp[j],dp[j-k]+A[i]*power(k,B[i]));
    cout << dp[v]<<endl;
    return 0;
}


inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline void write(int x)
{
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
阅读更多
版权声明:欢迎转载评论 https://blog.csdn.net/m0_37809890/article/details/79952458
个人分类: 题解
上一篇dp训练第20题 csu1326: The contest 分组背包 并查集
下一篇背包九讲学习笔记 第七讲-有依赖的背包问题 第八讲-泛化物品
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭