zoukankan      html  css  js  c++  java
  • [Algorithm] Meeting hour optimization (Kanpsack problem) and Dynamic programming

    For example we have array of meeting objects:

    const data = [
      { name: "m1", hours: 2 },
      { name: "m2", hours: 4 },
      { name: "m3", hours: 3 },
      { name: "m4", hours: 3 },
      { name: "m5", hours: 1 }
    ];

    For a day, 8 hours, we want to take as any meetings as possible:

    const res = optimizeMeetings(data, 8);

    You should write function 'optimizeMeetings', get the results of selected meetings to attend.

    This problem is the same as Knapack problem, we can construct a table:

    hours / total 1 2 3 4 5 6 7 8
    2  0  2  2  2  2  2  2
    4  0  2  2  4  4  6  6  6
    3  0  2  3  4  5  6  7 7
    3  0  2  3  4  5  6  7  8
    1  1  2  3  4  5  6  7 8

    The max hours we can take is the last row & col value, which in the end should be 8.

    Then we should trace back the table to find which items should be included.

     

    Final Code:

    /**@description
     * When we have our result for Knapsack problem, we want to back trace to get the selected items.
     *
     * What we need to do is trace form last item of the memo, moving up
     */
    const backTrace = (hours, totalHours, memo) => {
      function helper(memo, row, col) {
        let current = memo[row][col];
        let selected = [];
        while (current >= 0 && row >= 0 && col >= 0) {
          // If we reach the first row, then check whether we have the remaining?
          // If yes then we need to add this row item into final result
          if (row === 0 && current !== 0) {
            selected.push(row);
            break;
          }
    
          let sameRowPrevCol = memo[row][col - 1];
          let prevRowSameCol = memo[row - 1][col];
    
          if (current !== sameRowPrevCol && prevRowSameCol !== current) {
            // Item should be selected if the value with sibling values are differnet
            selected.push(row);
            // calcuate the remaining
            col = current - hours[row] - 1;
            row = row - 1;
          } else if (prevRowSameCol === current && current !== sameRowPrevCol) {
            // current is coming from previous row with the same column, reset row
            row = row - 1;
          } else if (current === sameRowPrevCol && prevRowSameCol !== current) {
            // current is coming from previous column with the same row, reset column
            col = col - 1;
          }
          // Update current with new row and new column
          current = memo[row][col];
        }
        return selected;
      }
    
      return helper(memo, hours.length - 1, totalHours.length - 1);
    };
    
    const getMaxHours = (hours, totalHours) => {
      let memo = [...new Array(hours.length)].map(
        x => new Array(totalHours.length)
      );
      function helper(hours, totalHours, memo) {
        for (let row in hours) {
          const value = hours[row];
          for (let col in totalHours) {
            // Fill in the first row
            if (!memo[row - 1]) {
              memo[row][col] = value <= totalHours[col] ? value : 0;
              continue;
            }
    
            // if the current value is larger than constrain, we use previous value
            const prevRowSameCol = memo[row - 1][col];
            if (value > totalHours[col]) {
              memo[row][col] = prevRowSameCol;
              continue;
            }
    
            // if the current value is equal to constrain, then Max{value, prevRowSameCol}
            if (value === totalHours[col]) {
              memo[row][col] = Math.max(value, prevRowSameCol);
            }
    
            // if the current value is smaller than constrain
            // Math {value + memo[row - 1][diff]: where diff is constrain-value, prevRowSameCol}
            if (value < totalHours[col]) {
              const diff = totalHours[col] - value - 1;
              memo[row][col] = Math.max(
                prevRowSameCol,
                value + memo[row - 1][diff]
              );
            }
          }
        }
        return memo;
      }
      memo = helper(hours, totalHours, memo);
      const selectedIndex = backTrace(hours, totalHours, memo);
    
      return {
        memo,
        selectedIndex
      };
    };
    
    function* genearteNumberAry(start, num) {
      let i = start;
      while (i <= num) {
        yield i;
        i++;
      }
    }
    
    /**
     * Main
     */
    /**
     * @param meetings: [{name: string, hours: number}]
     * @param haveHours: number
     *
     * @returns [meetings]
     */
    function optimizeMeetings(meetings, haveHours) {
      const hours = meetings.map(m => m.hours);
      const haveHoursAry = Array.from(genearteNumberAry(1, haveHours));
      const { selectedIndex } = getMaxHours(hours, haveHoursAry);
      return selectedIndex.map(i => meetings[i]);
    }
    
    const data = [
      { name: "m1", hours: 2 },
      { name: "m2", hours: 4 },
      { name: "m3", hours: 3 },
      { name: "m4", hours: 3 },
      { name: "m5", hours: 1 }
    ];
    
    const res = optimizeMeetings(data, 8);
    console.log(JSON.stringify(res)); // [{"name":"m4","hours":3},{"name":"m3","hours":3},{"name":"m1","hours":2}]
  • 相关阅读:
    求正方形的面积和周长
    面向对象练习——校园管理系统
    python--面向对象(最全讲解)
    git删除远程仓库的文件或目录
    git设置忽略文件和目录
    计算器
    织梦标签整理
    比较恶心的360老年版浏览器 文件导出下载
    织梦文章列表样式多元化实现
    php函数整理
  • 原文地址:https://www.cnblogs.com/Answer1215/p/10539674.html
Copyright © 2011-2022 走看看