• 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才能运行通过。

  • 相关阅读:
    架构师如何才能够设计一个安全的架构
    Google Analytics实用用小技巧
    如何从Linux系统中删除用户账户
    使用C++编译器的编译流程
    JavaScript中双叹号的使用实例
    Android合并文件的三种方式代码
    自学Linux命令的四种方法
    前端工程师必备实用网站
    给 iOS App 开发者的 39 个开源的 Swift UI 库
    关于iOS项目的一本书
  • 原文地址:https://www.cnblogs.com/aicanxxx/p/6892948.html
Copyright © 2020-2023  润新知