【动态规划】气球游戏

题目描述

刚刚今天去游乐场玩,发现了一个新的游戏项目,游戏是这样的,场上一共有 n 个气球,它们的编号是0到n-1,然后每个气球上还有一个数字,我们使用数组nums来保存这些数字。

现在游戏要求刚刚戳破所有的气球。每当刚刚戳破一个气球i时,刚刚可以获得nums[left] * nums[i] * nums[right]个积分。这里的left和right指的是和i相邻的两个气球的序号。(注意每当刚刚戳破了气球i后,气球left和气球right就变成了相邻的气球。)

求所能获得积分的最大值。

输入数据

输入中有若干组测试样例,第一行为一个正整数T(T≤1000),表示测试样例组数。每组测试样例包含2部分: 第一部分有一行,包含1个正整数n(0≤n≤500),第二部分为一行,有n个数,第i个数表示num[i],(0≤num[i]≤100)。

输出数据

对每组测试数据,单独输出一行答案,表示最大的积分值。

在这里插入图片描述

#include<stdio.h>
#include<math.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<string.h>
using namespace std;
#define N 100000+5
const double eps = 1e-15;

int n, num[505];

long long dp[505][505];//dp[i][j]: 第i~j个气球组合的最大分值

int main() {
    int T;
    cin >> T;
    while(T--) {
        memset(num, 0, sizeof(num));
        memset(dp, 0, sizeof(dp));
        cin >> n;
        for (int i = 1; i <= n; i++)
            cin >> num[i];
        if (n == 0) {
            cout << 0 << endl;
            continue;
        }
        num[0] = 1, num[n+1] = 1;
        for (int i = 1; i <= n; i++)
            dp[i][i] = num[i-1] * num[i] * num[i+1];
        for (int len = 1; len <= n-1; len++)
            for (int i = 1; i <= n; i++) {
                int j = i + len;
                if (j > n) break;
                //枚举这一段最后一个扎爆的气球
                long long max_num = -1;
                for (int k = i; k <= j; k++) {
                    max_num = max(max_num, dp[i][k - 1] + dp[k + 1][j] + num[i - 1] * num[k] * num[j + 1]);
                }
                dp[i][j] = max_num;
            }
        cout << dp[1][n] << endl;
    }
    return 0;
}

总结:
最开始思路错了,转移方程如果设计为max(dp[i][k - 1] + dp[k + 1][j] + num[k - 1] * num[k] * num[k + 1]),这样会有一个问题,我们把k扎爆了,[i, k - 1]这一段我们扎k-1的话,它右边的那个气球是谁我们就不知道了。所以要枚举最后一个扎爆的气球,加上num[i - 1] * num[k] * num[j + 1]。状态计算的过程要从[i, j]的长度由小到大进行枚举,最后的dp矩阵是一个三角矩阵(i>j全0)。结果还要注意对n==0特判一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值