51nod 3180 矩阵连乘

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;
}

posted @ 2024-09-10 18:58  sad_lin  阅读(3)  评论(0编辑  收藏  举报