fjut 【祖传第四周寒假作业】L题 T^T与小彩的爱情故事

先上题

Problem Description

上集说到,因为T^T帮助小彩解决了那道ACM的题目,于是小彩就把手机号给了T^T,T^T拿到手机号之后,高兴地快要疯了,于是每天都给人家嘘寒问暖,然后有个

周末,T^T终于把小彩给约出来了。可是小彩还是不放心把自己交给T^T,不知道他是不是真的那么厉害,于是又出了一道题给T^T,看看他是不是真的那么厉害。

 有n个硬币,每个硬币的价值为A1,A2,A3...An,每种对应有C1,C2,C3...Cn,然后小彩要T^T求:

 这些硬币所能组成的价值小于等于m的有多少种?

Input

输入包含多组测试数据.

第一行是两个整数n(1<=n<=100),m(m<=100000). 

第二行是2n个整数, 依次是A1,A2,A3...An,C1,C2,C3...Cn (1<=Ai<=100000,1<=Ci<=1000).

输入以0 0结束

Output

输出只有一行,包含一个整数

SampleInput
8
4


先贴下核心代码,value表示硬币价值,number表示硬币个数,dp表示对应到m的数值点。
int value[105],dp[100005],number[105];
dp[0]=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<=m;j++)
            {
                if(dp[j]>=0)
                {
                    dp[j]=number[i];//对于之前已经有的数,在这一点上不需要取第i轮的硬币,硬币个数即为他所有的个数
                }
                else
                {
                    if(j<value[i]||dp[j-value[i]]<0)//对于比当前硬币价值更小的,除了之前有的,他没法用一个当前硬币去取代当前的j值,或他当前的j值
                        //希望再取一个硬币,可是原来减去一个硬币的点上没有的取,即放弃。
                    {
                        dp[j]=-1;
                    }
                    else
                    {
                        dp[j]=dp[j-value[i]]-1;//取了一个硬币,要在之前的硬币个数上减1
                    }
                }
            }
        }
这题是一道很明显的多重背包问题,分解为单个硬币的多个数的可取与不可取问题。这题关键在于数据量特大,按照二维dp的想法,首先数组特大,容易mle(虽然自己没试过),其次数据量大,按照一开始的思路计算,3层for的
思路时间复杂度高达1e11,必然是不可取的。
这时候可以把它转换成对单个硬币分析,首先,对于取当前第i硬币,他有number[i]个,这时候,在dp[0]这个点,他一个都不少,那这时候dp[0]就要等于当前这个硬币的所有个数number[i],然后开始对于到m这个临
界点进行各个枚举,每一个点即用j进行表示。
第一种情况,如果这时候的j比当前硬币的价值小,说明他肯定是没法取一个硬币取代替当前这个值。第二种情况,如果dp[j-value[i]]的值是小于0,即之前所有情况都无法取到,那证明也没法去一个硬币取取代当前这个值。
第三种情况即为不符合上述2种情况的条件下,就可以用dp[j-value[i]]这个位置上的·硬币个数减一,因为可以用一个硬币去带掉。对于上一轮保存有值的地方,不需要考虑上述3种情况,就直接用number[i]取代他,因为这个有
值的地方不与当前这个硬币相关,所以不需要取。
最后对于最后一轮的结果进行枚举,只要dp[i]大于等于0,说明就有取过,拿个标记加合下就行。

猜你喜欢

转载自www.cnblogs.com/NVIDIA/p/10289374.html
今日推荐