DP-MinAbsSum

给定一个数组N个正整数,给每个数一个符号,正或者负使得所有数的的和的绝对值尽可能大。也就是使得这个
val(A, S) = |sum{ A[i]*S[i] for i = 0..N−1 }尽可能大s[i] = +1或者-1。
通过分析可以发现元素的正负不影响结果,问题转化为将数分成两堆,两堆只差最小。首先将元素全部转成正数顺便做了个count sort. 发现这个问题转化为多重背包问题。
DP背包参考http://wenku.baidu.com/view/cf9f0f8ecc22bcd126ff0c73.html

最开始只是将多重背包的代码原样copy过来,将每组数看作重量为i,value为i的物品,背包大小为sum/2。但是时间复杂度为N*N*A不满足要求。原因是背包里没有装东西,参考http://blog.youkuaiyun.com/caopengcs/article/details/10028269
将背包中装入达到重量j时剩余i的数量,如果无法达到为-1.

https://codility.com/demo/results/demoH2FANU-T7J/

class Solution {
    public int solution(int[] A) {
        // write your code in Java SE 8
        int[] hash = new int[101];
        int max = 0;
        int sum = 0;
        for(int i=0; i<A.length; i++){
            int a=Math.abs(A[i]);
            hash[a]++;
            sum+=a;
            max = Math.max(max,a);
        }

        //
        int half = sum/2+1;
        int[] dp = new int[half];
        for(int i=0; i<dp.length; i++){
            dp[i]=-1;
        }
        dp[0]=0;
        int can=0;
        // dp save the left number of item i to achive the sum j
        // -1 means sum 0-i < j
        for(int i=1; i<=max; i++){
            if(hash[i]>0){
                for(int j=0; j<dp.length; j++){
                    if(dp[j]>=0){
                        dp[j]=hash[i];
                        if(j>can){
                            can = j;
                        }
                    }
                    else{
                        if(j-i>=0 && dp[j-i]>0){
                            dp[j] = dp[j-i]-1;
                            if(j>can){
                                can = j;
                            }
                        }
                    }

                }
            }
            if(can>=half) break;
        }
        return Math.abs(sum-(can<<1));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值