uva-12563-01背包+输出最优解

本文介绍了一种改进的01背包问题解决方法,通过特殊初始化dp数组来准确记录每首歌的确切演唱时间,并详细解释了代码实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个题有几个点注意:

1.给出的唱歌时间总长度是1e9,实际上只有3*60*50=9000s。所以背包的前提满足。

2.唱歌时间是t,但是必须留出来1s唱Jin Ge Jin Qu,所以背包时容量最大为t-1。

3.在这个题我们称输出的时间是“恰好的时间”(都能理解),但是一般的背包记录的是在当前容量能唱的歌的数量,这样当样例是     

3 100

60 70 80  这种情况时,从60到80,dp[j]都是1,所以不好找出哪个值是唱一首歌花的时间

这里给出的思路是:将一般的01背包的dp数组初始化为0,改为整个初始化为负的INF并且dp[0]=0。

这样就会导致,后面记录的dp[j]从60到80只有dp[60],dp[70],dp[80]这种“恰好的时间”的值是1,其他的在这之间的都是大于﹣INF且小于0的。

这是因为每次恰好时都是和dp[0]比较。

PS:连续遇到两个简单dp但是都不会输出路径QAQ

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
#include <queue>

using namespace std;

const int INF=0x3f3f3f3f;
int t,n,T;
int val[100];
int dp[10000];

int main()
{
    scanf("%d",&T);
    for(int k=1; k<=T; k++)
    {
        scanf("%d%d",&n,&t);
        for(int i=1; i<=n; i++)
            scanf("%d",&val[i]);
        t%=9000;//处理下唱歌时间
        memset(dp,-INF,sizeof(dp));
        dp[0]=0;//非常重要,这个地方只有初始化dp[0]为0,后面输出才简化很多,才能直接找到恰好的时间
        for(int i=1; i<=n; i++)
            for(int j=t-1; j>=val[i]; j--)
                dp[j]=max(dp[j],dp[j-val[i]]+1);//单纯的01背包
        //和上面对应,j-val[i]=0表示恰好装下,也就是我们要输出的
        //一般的背包统一初始化为0在这题会导致j>val[i]时背包值不是要输出的答案
        int ans=-INF,temp;//
        for(int i=t-1; i>=0; i--)//一定要i=0,因为可能总时间t不能唱任何一首歌,这样最大值就是容量为0时的值也就是0
            if(dp[i]>ans)//这个地方能找到的只有0和恰好唱的时间
                ans=dp[temp=i];//顺便记录这个时间
        printf("Case %d: %d %d\n",k,ans+1,temp+678);
    }
    return 0;
}

 

用回溯法解0_1背包问题时,会用到状态空间树。在搜索状态空间树时,只要其左儿子结点是一个可行结点,搜索就进入其左子树。当右子树有可能包含最优解时才进入右子树搜索,否则将右子树剪去。设r是当前剩余物品价值总和;cp是当前价值;bestp是当前最优价值。当cp+r≤bestp时,可剪去右子树。计算右子树中解的上界可以用的方法是将剩余物品依其单位重量价值排序,然后依次装入物品,直至装不下时,再装入该物品的一部分而装满背包。由此得到的价值是右子树中解的上界,用此值来剪枝。 为了便于计算上界,可先将物品依其单位重量价值从大到小排序,此后只要顺序考察各物品即可。在实现时,由MaxBoundary函数计算当前结点处的上界。它是类Knap的私有成员。Knap的其他成员记录了解空间树种的节点信息,以减少函数参数的传递以及递归调用时所需要的栈空间。在解空间树的当前扩展结点处,仅当要进入右子树时才计算上界函数MaxBoundary,以判断是否可以将右子树减去。进入左子树时不需要计算上界,因为其上界与父结点的上界相同。 在调用函数Knapsack之前,需要先将各物品依其单位重量价值从达到小排序。为此目的,我们定义了类Objiect。其中,运算符与通常的定义相反,其目的是为了方便调用已有的排序算法。在通常情况下,排序算法将待排序元素从小到大排序。 在搜索状态空间树时,由函数Backtrack控制。在函数中是利用递归调用的方法实现了空间树的搜索
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值