动态规划 所有火柴是否能拼接正方形

112 阅读1分钟

题目

320a633454682ffee8227df02f68b0f8.png

  • 递归模型为从左往右,通过一个位数组记录已经访问的内容
  • ....................
function main(arr) {
  let sum = 0;
  sum = arr.reduce((pre, now) => pre + now, 0);

  if (sum % 4 !== 0) {
    return false;
  }

  // dp 最多有 2^12 次方答案
  let dp = Array(1 << arr.length).fill(0);
  let len = sum / 4;

  return process(arr, 0, 0, len, 4, dp);

  // status 通过二进制每一位代表第 i 根火柴是否使用
  // sum 表示当前拼接边的长度
  // edges 表示还剩多少边没有拼接
  function process(arr, status, sum, len, edges, dp) {
    // 所有边都拼接完,并且每个火柴都使用
    if (edges === 0) {
      let n = arr.length;
      // 比如4根火柴:10000 - 00001 = 1111
      let s = (1 << n) - 1;
      return s === status ? true : false;
    }

    //
    if (dp[status] !== 0) {
      return dp[status] == 1;
    }

    let ans = falase;

    for (let i = 0; i <= arr.length; i++) {
      // 当前火柴没用过
      if (status & (1 << i === 0)) {
        // 并且使用当前火柴不能超过单边长度
        if (sum + arr[i] <= len) {
          if (sum + arr[i] < len) {
            ans = process(arr, status | (1 << i), sum + arr[i], len, edges);
          } else {
            ans = process(arr, status | (1 << i), 0, len, edges - 1);
          }
        }
      }
      if (ans) {
        break;
      }
    }
    // 记录当前 status 结果,主要是记录失败的结果
    dp[status] = ans ? 1 : -1;
    return ans;
  }
}