01背包-双核问题

题目来源自牛客网的网易算法题,如有侵权行为请告知删除。

题目是这样的:
  一种双核CPU的两个核能够同时的处理任务,现在有n个已知数据量的任务需要交给CPU处理,假设已知CPU的每个核1秒可以处理1kb,每个核同时只能处理一项任务。n个任务可以按照任意顺序放入CPU进行处理,现在需要设计一个方案让CPU处理完这批任务所需的时间最少,求这个最小的时间。
输入描述:
输入包括两行:
  第一行为整数n(1 ≤ n ≤ 50)
  第二行为n个整数length[i](1024 ≤ length[i] ≤ 4194304),表示每个任务的长度为length[i]kb,每个数均为1024的倍数。
输出描述:
  输出一个整数,表示最少需要处理的时间
输入例子:
  5
  3072 3072 7168 3072 1024
输出例子:
  9216

  这是一个01背包问题,总的处理时间为sum,要使所需时间最少,则两者的差值最小,假设cpu1处理时间为t(t<=sum/2),cpu2处理的时间为sum-t,当t最接近于sum/2时,sum-t也最接近sum/2,此时两者的差值最小,即时间最短。
  01背包问题是指容量为V的背包里放进n个物品,其中第i个物品的重量或体积为c[i],价值为w[i],哪些物品放进去会使价值总和最大,这个物品只有放或者不放这两种选择,不能重复放或者放一半,故称为01背包问题。该算法的状态转移方程为:

    f[i][v]=max(f[i-1][v],f[i-1][v-c[i]]+w[i])

其中,f[i][v]是容量为v时放进第i件物品的价值,当第i件物品不放进去时就等于之前i-1件物品放进容量为v的背包的价值之和,当第i件物品放进去时就等于之前i-1件物品放进容量为v-c[i]的背包的价值加上第i件物品的价值之和。

    //f的初始值为0
    for(i = 1; i<=n; i++)  //i从1开始    
    {  
        for(j = v; j>=c[i]; j--) //j的值从v到c[i],即物品可以放进去
        {  
            f[i][v]=max(f[i-1][v],f[i-1][v-c[i]]+w[i]);  
        }  
    }  

由于f[i][v]是二维数组,是指前i件物品的价值总和,而f[i][v]是由前i-1件物品的价值总和得来的,故可对数组进行优化,将二维数组优化成一维的,即

    //f的初始值为0
    for(i = 1; i<=n; i++)  //i从1开始    
    {  
        for(j = v; j>=c[i]; j--) //j的值从v到c[i],即物品可以放进去
        {  
            f[v]=max(f[v],f[v-c[i]]+w[i]);//用i时刻的f[v]的值覆盖i-1时刻的f[v]  
        }  
    }  

在下一个循环进行前,此时f[v]就是i-1时刻的f[v],通过获取最大值操作,用i时刻的值覆盖i-1时刻的值,这样与前面的二维数组是等效的,但是复杂度降低了。

  从该题目中抽象出来背包问题为:总任务量为sum的双核cpu有n个任务需要处理,每个任务长度为arr[i],所需要花费的时间为arr[i],对于cpu1来说,假设cpu1处理时间为t(t<=sum/2),要怎样处理任务才能使处理的任务时间最接近sum/2。
程序如下:

    process.stdin.resume();//回复输入流
    process.stdin.setEncoding('utf8');

    var input_stdin = "";//输入的全部数据
    var input_stdin_array = "";//输入的每行数据以数组形式存在
    var input_currentline = 0;//输入的行数

    process.stdin.on('data', function (data) {//接收输入的数据
        input_stdin += data;
        if(data.slice(0,-1)==''){
            process.stdin.emit('end');//输入空的回车结束输入
        }
    });

    process.stdin.on('end', function () {//end触发
        input_stdin_array = input_stdin.split("
");
        main();//对输入进行操作
    });

    function readLine() {
        return input_stdin_array[input_currentline++];//读取每一行的数据
    }

    function main(){
        var n=readLine();
        var arr=readLine().split(' ');
        var sum=0,dp=[],t=0;
        arr=arr.map(function(item){//从字符变成数字
            return +item;
        });
        for(let i=0;i<n;i++){
            arr[i] /= 1024;
            sum +=arr[i];
        }
        for(let i=0;i<sum;i++){
            dp[i]=0;
        }
        for(let i=0;i<n;i++){
            for(let j=parseInt(sum/2);j>=arr[i];j--){
                dp[j]=Math.max(dp[j],dp[j-arr[i]]+arr[i]);
            }
        }
        t=Math.max(dp[parseInt(sum/2)]*1024,(sum-dp[parseInt(sum/2)])*1024);
        console.log(t);
    }

牛客网不支持ES6,需将let改成var才能运行通过。

原文地址:https://www.cnblogs.com/aicanxxx/p/6892948.html