Multiplication Puzzle (poj 1651)

本文介绍了一种使用动态规划解决特定序列删除问题的方法。该问题要求从整数序列中依次删除元素,使得删除的总代价最小。文章详细分析了解决方案,并提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意

给出一个整数序列,从中依次删除元素,如果删除元素card[i],就把card[i]card[i1]card[i+1]加到删除的代价里。求最小的删除代价。不允许删除最左和最右的元素。在删除结束后,序列只剩下两个元素。

分析

动态规划。第一眼就可以看出和矩阵乘法很像。
自顶向上考虑问题。考虑最后一次删除,设最后一次删除的元素是card[k],那么删除的代价是card[0]card[n1]card[k]+S[0][k]+S[k][n1],其中S[0][k]表示删除序列card[0,1,...,k]需要的代价,S[k][n1]表示删除序列card[k,k+1,...,n1]所需要的代价。
注意每次序列删除最终都会留下头和尾,所以是S[0][k]而不是S[0][k1].
边界条件:需要让S[i][i+1]=0

代码

#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <string>
#include <string.h>
#include <queue>
#include <set>
#include <limits.h>
using namespace std;

// multiplication puzzle
// 找一个符合条件的顺序,暴力方法是O(n!)
// 动态规划
// S[i,j] = min(S[i,k] + S[k,j] + A[i]A[k]A[j]) if j-i > 2, k >i && k <j
// S[i,j] = A[i]*A[i+1]*A[j] if j-i=2
const int MAXN = 105;
int cards[MAXN];
int S[MAXN][MAXN];  //动态规划数组,S[i][j]表示以i开头以j结尾的链的最小乘积
void dp(int n) {
    for (int r = 3; r <= n; r++) {
        // r是链长
        for (int i = 0; i < n - r + 1; i++) {
            // i是链头
            int j = i + r - 1; //j是链尾
            cout << i << " " << j << endl;
            // 接下来求S[i][j]
            int min_k = -1;
            for (int k = i+1; k < j; k++) {
                // k是要选择剔出的数的下标
                int left = S[i][k]; // S[i][i]初始化为0,其余初始化为最大值
                int right = S[k][j];
                int tmp_res = left + right + cards[i] * cards[k] * cards[j];
                cout << left << " " << right << " " << tmp_res << endl;
                if (tmp_res < S[i][j]) {
                    S[i][j] = tmp_res;
                    min_k = k;
                }
            }
            cout << "k: " << cards[min_k] << endl;
        }
    }
}
int main() {
    int n; 
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> cards[i];
    }
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            S[i][j] = INT_MAX;
        }
    }
    for (int i = 0; i < n; i++) {
        S[i][i] = 0;
    }
    for (int i = 0; i < n - 1; i++) {
        S[i][i + 1] = 0;
    }
    dp(n);
    cout << S[0][n - 1] << endl;
    return 0;
}

反思

因为一开始就觉得是矩阵乘法,所以直接开始写矩阵乘法的代码。但是因为没有考虑清楚整个问题,所以在边界上出错。实际还是对问题分析得不透彻。以后要认真分析问题,就题论题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值