首页 > 其他分享 >51nod 3180 矩阵连乘

51nod 3180 矩阵连乘

时间:2024-09-10 19:03:54浏览次数:1  
标签:连乘 51nod 矩阵 long int 3180 维度 dp

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

标签:连乘,51nod,矩阵,long,int,3180,维度,dp
From: https://www.cnblogs.com/sadlin/p/18406970

相关文章

  • 51nod 最大M子段和v1/v2/v3
    学习笔记最大M子段和V1\(N\)个整数组成的序列\(a[1],a[2],a[3],…,a[n]\),将这N个数划分为互不相交的\(M\)个子段,并且这\(M\)个子段的和是最大的。如果\(M>=N\)个数中正数的个数,那么输出所有正数的和。\(N,M<=5000\)。例如:\(-211-413-56-2\),分为\(2\)段,\(11......
  • 51nod 1051 最大子矩阵和
    51nod1051最大子矩阵和可以用前缀和容斥优化到\(O(n^4)\),但是不够进行如下图操作:将每一列的数值都压缩到一维的数组上,就转换为求最大字段和问题,时间复杂度\(O(n^3)\)。看看代码就知道了。#include<bits/stdc++.h>usingnamespacestd;#definelllonglongintn,m;......
  • 51nod 1243 排船的问题
    51nod1243排船的问题求最长绳子最短,考虑二分答案,判断时我们优先向左放,看是否能全放下。#include<bits/stdc++.h>usingnamespacestd;#definelllonglongintn,x,m;intpos[50005];intcheck(intmid){ intp=x;//偏差地图 intx2=x*2; intmx=m+x;//偏差地图 ......
  • 51nod 1020 逆序排列
    51nod1020逆序排列学习笔记其实要预处理,但唐的我非要每次都求一遍。设状态为\(dp[i][j]\)选了i个数逆序对数为j的排序种类数。首先初始化\(dp[i][0]=1\)即没有逆序对,转移方程\(dp[i][j]=dp[i-1][j]+dp[i-1][j-1]+……+dp[i-1][j-i]\)这是显然的(放上这个数,会产生的......
  • 51nod 1296 有限制的排列
    题目链接学习链接设状态\(dp[i][j]\)表示整数\([1,i]\)满足要求的排列中,最后一个数选\(j\)的排列数。开一个数组记录他的状态:把前面已选好的序列中大于等于\(j\)的数都加一后再把\(j\)加到后面。#include<bits/stdc++.h>usingnamespacestd;#definelllong......
  • 51nod 1050 循环数组最大子段和
    51nod1050循环数组最大子段和虽然是板子题,两种做法,我们先写一种,另一个咕咕。因为是循环,所以分为两种,中间的和两边的,中间的直接dp求最大,两边的转化一下就是总的数字和减去中间的最小数字和。#include<bits/stdc++.h>usingnamespacestd;#definelllonglonglla[500005]......
  • 51nod 1791 合法括号子段
    51nod1791原题链接因为在括号串固定的情况下,括号的匹配是固定不变的。所以对左括号进行匹配,p[i]表示与i这个括号相匹配的括号的位置,易得到dp方程ans[i]=ans[p[i]+1]+1,然后再从后先前一遍求和即可。#include<bits/stdc++.h>usingnamespacestd;#definelllonglongconst......
  • 51nod 石子分配
    可以发现步数限制把数轴变为了环。环之间不可以交换,环内相邻两点可以交换,然后我们只需要对每个环操作,最后累加。对于环上的每个石子堆,我们需要将其石子数调整到均值\(avg\)。因此,我们首先计算每个堆石子相对于\(avg\)的偏差,即\(nowa[i]-avg\)。因为相邻节点不一定能凑齐......
  • 51nod 1110 距离之和最小
    51nod1110距离之和最小考虑贪心取中位数,因为中位数到左边的点和右边的点的个数相同,更合理,权值的话可以转化为一个单点,然后没了。#include<bits/stdc++.h>usingnamespacestd;#definelllonglongintn;structss{ llx,w;}a[100005];boolcmp(ssg,ssh){ return......
  • 51nod 1383 整数分解为2的幂
    整数分解为2的幂这题非常厉害,建议认真看下去虽然我讲的也不好。首先肯定先想到的是多重背包,可以把每个次幂当作物品,然后套板子。但是这题有\(O(n)\)复杂度的做法,我们想如果一个数\(i\)是奇数,那他只能由\((i-1)+1\)转化过来(2的幂次只有1是奇数),那方案数就是\(i-1\)的方案......