【问题标题】:How to convert this recurrence solution to divide and conquer?如何将这种递归解决方案转换为分而治之?
【发布时间】:2020-01-19 11:46:04
【问题描述】:

如何解决这个问题:

给定 n 个气球,索引从 0 到 n-1。每个气球都涂有 其上的数字由数组 nums 表示。你被要求爆裂所有 气球。如果你爆破气球 i 你会得到 nums[left] * nums[right] 个硬币。这里 left 和 right 是 i 的相邻索引。 爆裂后左右就相邻了。如果你爆裂了 角气球然后你会得到相邻的点 那些气球。如果你爆了最后一个气球,那么你会得到 写在上面的点数。找到你能找到的最大硬币 明智地爆破气球来收集。

示例测试用例:

{1,2,3,4}
20
{5,7,8}
56

我已经使用递归尝试了这个解决方案,似乎给出了正确的答案:

public static int maxCoints(List<Integer> list) {
        int max = 0;
        if (list.size() == 1) {
            return list.get(0);
        }
        if(list.size() == 2) {
            return Math.max(list.get(0),list.get(1))*2;
        }
        for (int i = 0; i < list.size(); i++) {
            int left = i == 0 ? 1 : list.get(i-1);
            int right = i == list.size()-1 ? 1 : list.get(i+1);
            int n = left * right;
            List<Integer> tmp = new ArrayList<>(list);
            tmp.remove(i);
            max = Math.max(max, n + maxCoints(tmp));
        }
        return max;
    }

但是我已经尝试过这种分而治之的解决方案,但它似乎对第一个测试用例给出了错误的答案,这给出的答案是 17 而不是 20

int find(vector<int>& v, int L, int R) {
    int ans = 0;
    // if(L==R)    return v[L];
    for (int i = L; i <= R; i++) {
        int l = find(v, L, i-1);
        int r = find(v, i+1, R);
        int val = v[L-1]*v[R+1] + l + r;
        ans = max(ans, val);
    }
    return ans;
}

int32_t main() {
fast_io;
    ll tt;  cin >> tt;
    while(tt--) {
        ll n;   cin >> n;
        vector<int> v(n+2,1);
        for(int i=1;i<=n;i++) {
            cin >> v[i];
        }
        cout << find(v,1,n) << "\n";
    }
    return 0;
}

请帮我找出错误。

【问题讨论】:

  • 版主说明:请勿破坏帖子;根据您发布它的那一刻,它已被许可给该网站的条款和条件。我们不会在获得答案后删除问题,因为发布的解决方案可能对未来的访问者有所帮助。
  • (看来我昨晚不小心清除了您要求删除的标志,通常会被拒绝。如果造成混乱,我深表歉意)。

标签: java c++ algorithm


【解决方案1】:

这似乎是我编写编辑解决方案的burst balloons problem on leetcode 的一个小修改。

递归会起作用,但就我们的意图和目的而言,它太慢了。递归删除每个气球并缓存给我们2^N 状态,这是我们气球的力量集。我们想在多项式时间内解决这个问题。

分而治之绝对是正确的想法。

  • 爆破气球i后,我们可以将问题分为inums[0:i])左边的气球和inums[i+1:])右边的气球。

  • 为了找到最佳解决方案,我们在每个气球爆破后检查每个最佳解决方案。

  • 1234563 O(N^3)解决方案
  • 但是,如果我们尝试按照首先爆破气球的顺序来划分问题,就会遇到问题。当气球爆裂时,其他气球的相邻性会发生变化。我们无法跟踪间隔的端点与哪些气球相邻。这是您的解决方案存在问题的地方。

详细说明最后一点:

当你这样做时:

int l = find(v, L, i-1);

您实际上可能无法获得最佳解决方案。考虑到气球 i - 1 在您爆破气球 i 后现在与气球 i + 1 相邻。如果您随后将气球 i - 1 爆裂,则气球 i - 2 现在与气球 i + 1 相邻。如果您尝试在每个气球爆裂时进行除法,您的find 必须以某种方式仍然考虑[L, R] 范围之外的气球。

为了解决这个问题,我们考虑将气球添加到最初为空的区间中,而不是让气球爆裂和分开。

dp(i, j) 表示[i, j] 上的最高分。对于[i + 1, j - 1] 上的每个气球k,我们将其添加到区间中并计算分数。添加气球后,我们总是可以将问题分为[i, k][k, j],因为左右边界是已知的。这消除了邻接问题。

一个更棘手的部分是实现“如果你爆破最后一个气球,那么你将获得上面写的点数。”我们手动迭代我们爆裂的最后一个气球,并像以前一样应用分而治之。

查看代码以获得更好的想法:


class Solution {
    public int maxCoins(int[] nums) {

        int n = nums.length + 2;
        int[] new_nums = new int[n];

        for(int i = 0; i < nums.length; i++){
            new_nums[i+1] = nums[i];
        }

        new_nums[0] = new_nums[n - 1] = 1;

        // cache the results of dp
        int[][] memo = new int[n][n];

        // find the maximum number of coins obtained from adding all balloons from (0, len(nums) - 1)
        int ans = 0;

        // manually burst the last balloon because it has special rules
        for(int i = 1; i < n; ++i){
            ans = Math.max(ans, new_nums[i] + dp(memo, new_nums, i, n - 1) + dp(memo, new_nums, 0, i));
        }
        return ans;
    }

    public int dp(int[][] memo, int[] nums, int left, int right) {
        // no more balloons can be added
        if (left + 1 == right) return 0;

        // we've already seen this, return from cache
        if (memo[left][right] > 0) return memo[left][right];

        // add each balloon on the interval and return the maximum score
        int ans = 0;
        for (int i = left + 1; i < right; ++i)
            ans = Math.max(ans, nums[left] * nums[right]
            + dp(memo, nums, left, i) + dp(memo, nums, i, right));
        // add to the cache
        memo[left][right] = ans;
        return ans;
    }
}

输入:

[1, 2, 3, 4]
[5, 7, 8]

输出:

20
56

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-14
    • 2020-06-07
    • 1970-01-01
    • 2019-09-27
    • 2012-07-26
    • 2016-02-15
    • 2019-06-26
    • 2014-08-20
    相关资源
    最近更新 更多