首页 > 试题广场 >

牛能和牛可乐的礼物

[编程题]牛能和牛可乐的礼物
  • 热度指数:3796 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
众所周知,牛能和牛可乐经常收到小粉丝们送来的礼物,每个礼物有特定的价值,他俩想要尽可能按照自己所得价值来平均分配所有礼物。

那么问题来了,在最优的情况下,他俩手中得到的礼物价值和的最小差值是多少呢?
p.s 礼物都很珍贵,所以不可以拆开算哦

示例1

输入

[1,2,3,4]

输出

0

说明

他俩一个人拿1,4 。另一个人拿2,3
示例2

输入

[1,3,5]

输出

1

说明

他俩一个人拿1,3.另一个人拿5

备注:
单个礼物价值不超过100,礼物个数小于100,所有礼物总价值不超过10000
//方法一:
//这种方法也就是暴力搜索了,先对整个数组进行排序,差值最小,确认数组长度n,
//肯定先从数组末尾开始找,如若数组末尾数大于前n-1项和,则停止搜索,否则加上数组最小的数值,在对其他项相加求和,进行比较
//以此类推:
//文字有些难以理解,举个简单的例子[1,2,3,4,5],第一步:5<1+2+3+4;第二步:5+1<4+3+2;第三步:5+1+2>4+3;最后最小差值
//就为8-7=1;但是这个代码好像比较low,只能通过用例,不能a,哈哈;
class Solution {
public:
    /*
     * 
     * @param presentVec int整型vector 每个礼物的价值
     * @return int整型
     */
    int Sum_Array(vector<int>&presentVec,int a,int b){
        int sum=0;
        for(int i=a;i<b;i++){
            sum+=presentVec[i];
        }
        return sum;
    }
    int maxPresent(vector<int>& presentVec) {
        // write code here
        int n=presentVec.size();
        if(presentVec.size()==2)return abs(presentVec[0]-presentVec[1]);
        int sumA=0;
        int sumB=presentVec[n-1];
        sort(presentVec.begin(),presentVec.end());
        for(int i=0;i<n-1;i++){
            sumA+=presentVec[i];
        }
        if(sumB>=sumA)return sumB-sumA;
        else{
            for(int i=0;i<n-1;i++){
                sumB+=presentVec[i];
                sumA=Sum_Array(presentVec,i+1,n-1);
                if(sumB>=sumA)return sumB-sumA;
            }
        }
    }
};
//方法2:这个方法就比较巧妙了,还是借鉴牛客上其他大佬的思路,写出来的,理解了就好,代码挺简单的
//01背包问题,两个分组的值越接近总和一半差值越小,
//将总和一半看作背包的最大容量,每次放入的数字就是每次的体积,最后做差返回即可
class Solution{
public:
    int maxPresent(vector<int>& presentVec) {
        int sum=0;
        for(auto num:presentVec){
            sum+=num;
        }
        int split_sum=sum/2;
        vector<int>dp(split_sum+1,0);
        for(int i=0;i<presentVec.size();i++){
            for(int j=split_sum;j>=presentVec[i];j--){
                dp[j]=max(dp[j],dp[j-presentVec[i]]+presentVec[i]);
            }
        }
        return (sum-2*dp[split_sum]);//你仔细品,哈哈
    }
};

发表于 2020-11-04 21:08:02 回复(0)
class Solution {
public:
    /**
     * 
     * @param presentVec int整型vector 每个礼物的价值
     * @return int整型
     */
    int maxPresent(vector<int>& presentVec) {
        int s = 0;
        for(auto &x: presentVec)
            s += x;
        int V = s/2, dp[V+1];
        memset(dp, 0, sizeof(dp));
        for(auto &x: presentVec)
            for(int j=V;j>=x;j--)
                dp[j] = max(dp[j], dp[j-x]+x);
        return abs(s-2*dp[V]);
    }
};

发表于 2020-08-10 15:48:07 回复(0)
#
# 
(5842)# @param presentVec int整型一维数组 每个礼物的价值
# @return int整型
(5843)#
class Solution:
    def maxPresent(self , presentVec ):
        # write code here
        s = sum(presentVec)
        bv = s//2 + 1
        dp = [0]*bv
        for i in range(len(presentVec)):
            for j in range(bv-1, presentVec[i]-1, -1):
                dp[j] = max(dp[j], dp[j-presentVec[i]] + presentVec[i])
        return s - dp[bv-1] - dp[bv-1]
01背包问题,两个分组的值越接近总和一半差值越小,将总和一半看作背包的最大容量,每次放入的数字就是每次的体积,最后做差返回即可
发表于 2020-05-18 02:24:16 回复(0)
int maxPresent(vector<int>& presentVec) {
        int sum = 0,size=presentVec.size();
        for(int i=0;i<size;i++)sum+=presentVec[i];
        vector<int>dp(sum/2+1,0);
        for(int i=0;i<size;i++){
            for(int j=sum/2;j>=presentVec[i];j--){
                dp[j] = max(dp[j],dp[j-presentVec[i]]+presentVec[i]);
            }
        }
        int res=2*dp[sum/2]-sum;
        return res>=0?res:-res;
    }

发表于 2020-04-10 11:55:11 回复(0)
  • 将问题转化为0-1背包问题来解决
  • 思路:我们取礼物价值总和数的一半(向上取)来作为我们背包的容量,我们要尽可能地去填满这个背包,这样差值就是最小
import java.util.*;
public class Solution {
    /**
     * 
     * @param presentVec int整型一维数组 每个礼物的价值
     * @return int整型
     */
    public int maxPresent (int[] presentVec) {
        // write code here
        int n = presentVec.length;
        if(n == 0) return 0;
        int sum = 0;
        for(int i = 0; i < n; i++){
            sum += presentVec[i];
        }
        //简化为背包问题
        int v = (sum + 1) / 2;
        int[] dp = new int[v+1];
        for(int i = 0; i < n; i++){
            int p = presentVec[i];
            for(int j = v; j >= p; j--){
                dp[j] = Math.max(dp[j], dp[j-p]+p);
            }
        }
        int result = 2*dp[v] - sum;
        return  result >= 0 ? result : -result;
    }
}
发表于 2020-03-27 00:44:13 回复(0)
dp难理解我们完全可以用记忆化搜索
int maxPresent(vector<int>& presentVec) {
        // write code here
        int sum = 0;
        int n = (int)presentVec.size();
        for (int i = 0; i < n; i++) {
            sum += presentVec[i];
        }
        vector<int> dp(sum + 1, -1);
        auto dfs = [&](auto&& self, int foo, int idx)->int {
            if (dp[foo] != -1) {
                return dp[foo];
            }
            if (idx == n) {
                dp[foo] = (int)abs(sum - foo - foo);
                return dp[foo];
            }
            dp[foo] = min(self(self, foo + presentVec[idx], idx + 1),
                         self(self, foo, idx + 1));
            return dp[foo];
        };
        
        return dfs(dfs, 0, 0);;
    }


发表于 2020-03-25 20:26:11 回复(0)
装换为背包问题: 在 sum/2容量的背包中最多可以容纳的物品重量
public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * @param presentVec int整型一维数组 每个礼物的价值
     * @return int整型
     */
    public int maxPresent (int[] presentVec) {
        // write code here
        // 这不是背包问题吗?
        Arrays.sort(presentVec);
        int n = presentVec.length;
        int sum=0;
        for(int p:presentVec){
            sum+=p;
        }
        int target=sum/2;
        //sum是背包,东西不可重复装
        //dp[i][j]  表示前 i 个物品 装入 重量为j的背包的最大重量
        int [][] dp = new int[n+1][target+1];
        for(int i=1;i<=n;++i){
            for(int j=1;j<=target;++j){
                if(j>=presentVec[i-1]){
                    dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-presentVec[i-1]]+presentVec[i-1]);
                }else{
                    dp[i][j] = dp[i-1][j];
                }
            }
        }
        return Math.abs(sum-2*dp[n][target]);
    }
}

发表于 2021-04-03 07:39:58 回复(0)
import java.util.*;


public class Solution {
    /**
     * 
     * @param presentVec int整型一维数组 每个礼物的价值
     * @return int整型
     * 典型的01背包问题
     */
    public int maxPresent (int[] presentVec) {
        // write code here
        int sum = 0;
        int value = 0;
        for (int i = 0; i < presentVec.length; i++){
            sum = sum+ presentVec[i];
            value = sum/2;
        }
        int[][] dp = new int[presentVec.length+1][value+1];
        for (int i = 1; i < presentVec.length+1; i++){
            for (int j = 1; j < value + 1; j++){
                if (presentVec[i-1] > j){
                    dp[i][j] = dp[i-1][j];
                }else if (presentVec[i-1] == j){
                    dp[i][j] = Math.max(presentVec[i-1], dp[i-1][j]);
                }else{
                    dp[i][j] = Math.max(dp[i-1][j-presentVec[i-1]]+presentVec[i-1], dp[i-1][j]);
                }
            }
        }
        int result = (sum - dp[presentVec.length][value]) - dp[presentVec.length][value];
        if (result < 0){
            return 0-result;
        }else{
            return result;
        }
    }
}
01背包问题。不懂搜一下视频讲解01背包得思路  然后就明白了
发表于 2020-09-20 17:19:02 回复(0)
import java.util.*;


public class Solution {
    /**
     * 
     * @param presentVec int整型一维数组 每个礼物的价值
     * @return int整型
     */
    public int maxPresent (int[] presentVec) {
        // write code here
        int n = presentVec.length;
        if(n == 0){
            return 0;
        }
        //求礼物总和
        int sum = 0;
        for(int i = 0; i < n;i++){
            sum += presentVec[i];
        }
        
        int v = sum / 2;
        int[] dp = new int[v+1];
        for(int i = 0; i < n;i++){
            for(int j = v;j >= presentVec[i];j--){
                dp[j] = Math.max(dp[j], dp[j-presentVec[i]]+presentVec[i]);
            }
        }
        
        int res = 2 * dp[v] - sum;
        return res >= 0 ? res : -res;
    }
}

发表于 2020-09-12 16:50:28 回复(0)
首先将为题转换为0-1背包问题,背包容积是全部数字和的一半,挑出最接近背包的数放入背包,这些书和没有放进背包的数的差就是最小的。然后就是根据0-1背包算法编写代码,根据空间复杂度的极致优化方法,进行编码。
class Solution:
    def maxPresent(self , presentVec ):
        zonghe = sum(presentVec)
        beibao = zonghe // 2  # 挑出最接近总和一半的数出来,在和另一半做差,就是做小的
        dp = [0 for i in range(beibao + 1)]  # 一维数组来存放每次一迭代的最优结果
        for i in range(len(presentVec)):
            for j in range(beibao, presentVec[i] - 1, -1):
            # 有公式知,需要右后向前更新,到presentVec[i]是因为再小就放不下这个数,不会有更大的更新值,保持上一次的值就可以
                dp[j] = max(presentVec[i] + dp[j - presentVec[i]], dp[j])
                # 0-1背包算法的更新公式,放入当前数值后剩下的体积,再放dp中保存的这个体积能放的最多的数,与更新前比较大小
        maxvalue = dp[beibao]  # 将dp最后一位,即背包体积能放下的最多的数
        return abs(maxvalue - (zonghe - maxvalue))  # 装入背包的和没有装入的差,就是最小值


发表于 2020-05-26 14:23:04 回复(0)
01背包
```
class Solution {
public:
    int maxPresent(vector<int>& presentVec) {
        int sum = 0;
        for(auto t: presentVec) sum += t;
        int V = sum / 2;
        vector<int> dp(V + 1, 0);
        for(auto t: presentVec)
        {
            for(int j = V; j >= t; j--)
                dp[j] = max(dp[j], dp[j - t] + t);
        }
        int ret = sum - dp[V] - dp[V];
        if(ret < 0) ret = -ret;
        return ret;
    }
};
```
发表于 2020-05-02 20:32:01 回复(0)
class Solution:
    def maxPresent(self , p ):
        # write code here
        if len(p) <= 0:
            return 0
        p.sort()
        pa = sum(p)
        if len(p) < 2:
            return p[0]
        dp = [[0 for i in range(pa+1)] for j in range(len(p))]
        dp[0][p[0]] = 1
        dp[0][0] = 1
        f = p[0]
        for i in range(1,len(p)):
            for j in range(f+1):
                dp[i][j] += dp[i-1][j]
                dp[i][j+p[i]]  = dp[i][j+p[i]] + 1 if dp[i-1][j] != 0 else 0
            f += p[i]
        res = dp[-1]
        m = pa
        for i in range(pa):
            if res[i] != 0:
                m = min(m,abs((pa-i)-i))
        return m
首先抠掉空、礼物只有一个这种边界条件
然后用dp建立二维数组。然后就是得到所有可能的加和情况,即dp最后一行,只要不为0则计算在此情况下差值,求最小即可
发表于 2020-04-07 12:51:35 回复(0)