题目:现在有n个物品,每一个物品都有一个价值,现在想将这些物品分给两个人,要求这两个人每一个人分到的物品价值总和相同(个数可以不同,总价值相同即可),剩下的物品就需要扔掉,现在想知道最少需要扔多少价值的物品才能满足要求分给两个人。
输入输出:一行输入一个整数n,代表物品的个数。接下来输入n个数,a[i]表示第i个物品的价值。输出一个数表示最少需要扔掉的价值。
个人思路:这题简单来说就是求最优解,使用动态规划的思想是没跑了,奈何本人动态规划算法学的太菜,花了近一天的时间,找了几道动态规划的题,调试多种各自特殊的情况才写出自认为完整的代码(应该是没有错的了)。唉,只能说工作真是不好找,算法题简直要命!
一、吐槽完毕,来说正题。要求扔掉的物品总价值最少,反过来其实就是求分配的物品总价值最多,并且要能够平分总价值给两人,也就是两人每个人得到的物品价值总和相同,物品数量无所谓。举例来说:加入有7个物品,价值分别为{12,5,30,25,33,10,18},经过计算可得最少要扔掉17价值的物品,即5和12,剩余的刚好可以分为{25,33}和{10,18,30},各58的价值,平分给两人。
二、我一开始的想法是将物品价值从小到大排序,然后从价值最小的开始剔除,先计算当前未剔除的物品总价值,然后除以2,再从未剔除的物品中寻找是否存在几个物品的价值总和等于除以2后的价值,如果存在,就不用再剔除了,之前剔除的就是最小的了;如果不存在,就继续剔除一个当前价值最小的物品,再进行判断,依此类推,直到求出结果。
三、初步的大体思路就是这样,那么首先要解决的就是如何判断未剔除的物品中是否存在几个物品的价值总和等于除以2后的价值。我们可以把这个问题看作是在一堆数中寻找和为定值的任意多个数,即判断是否存在几个数的和为指定的数。这个我参考了寻找和为定值的任意多个数这篇博客,方法很多,我选的是递归的方法。因为参考的博客是求所有种可能的组合,而我只需要进行判断,即只要找到一种组合,该组合中的数加起来等于指定的值,就符合要求,不需要求出所有种可能,计算时间没有他那么多,因此经过改良,符合本题的判断函数代码定义如下所示,函数的输入参数为物品的个数n,物品的价值集合p[n],以及当前价值总和的一半Sum,因为题目要求中没说明价值是否为整型,所有就定义为了double型。
int k = 0;
bool SumCheck(int n, double p[], double Sum) {
bool flag;
if (n <= 0 || Sum < 0)
return false;
if (k > 0)
{
if (Sum == p[n - 1])
return true;
}
//考虑取第n个数
k++;
flag = SumCheck(n - 1, p, Sum - p[n - 1]);
if (flag