51nod 3180 矩阵连乘
感觉区间 dp 还是要感性理解,但好像区间有套路的,这和石子合并很像,就根据题意模拟。
这个写法的区间比较巧妙,左右同时增加,相当于滑动窗口,因为一开始花费一个是0,所以注意dp的初始化。
#include<bits/stdc++.h>
using namespace std;int n; // 矩阵的个数
long long dp[1005][1005]; // 动态规划表,dp[i][j]表示从矩阵i到矩阵j的最小乘法次数
long long a[1005]; // 存储矩阵的维度,a[i]表示第i个矩阵的行数,a[i+1]表示它的列数int main(){ios::sync_with_stdio(false);cin >> n; // 输入矩阵的个数(注意:实际输入的a数组长度是n+1,因为矩阵个数n需要n+1个维度来描述)memset(dp, 0, sizeof dp); // 初始化动态规划表,初始时所有乘法次数都为0// 读取n+1个值,用于表示n个矩阵的维度for(int i = 0; i <= n; i++){cin >> a[i]; // 输入矩阵的维度信息}// 动态规划部分,计算最小乘法次数for(int len = 2; len <= n; len++){ // len是当前处理的矩阵子链长度,从2个矩阵开始int r = len; // 初始化右端点for(int j = 1; r <= n; j++, r++){ // j是左端点,r是右端点,遍历所有可能的子链区间[j, r]long long mi = 1e18; // 初始化mi为一个非常大的数,相当于无穷大for(int k = j; k < r; k++){ // 枚举分割点k,将矩阵链[j, r]分成[j, k]和[k+1, r]两部分// 计算分割成两部分的代价,再加上这两部分相乘的代价mi = min(mi, dp[j][k] + dp[k+1][r] + a[j-1] * a[k] * a[r]);}dp[j][r] = mi; // 保存子链[j, r]的最小乘法次数}}cout << dp[1][n]; // 输出从矩阵1到矩阵n的最小乘法次数return 0;
}