POJ1651-类似矩阵连乘有关问题
POJ1651-类似矩阵连乘问题
题意:给定n个数,每次取其中一个数(第一个数和最后一个数不能取),得分+=这个数乘以它左边的数和右边的数。要求最后的得分最小。
思路:因为开始知道这个题的DP方程和矩阵连乘的DP方程一样,所以一直根据方程想思路,结果想了很久都没想出来,最后看了评论区的大神提示,瞬间想通。看来自己实力还是很渣渣啊。。唉
我们假设只有a1,a2,a3三个数,那我们只能取a2,那最后的得分=a1*a2*a3; 假如有n个数,设k为最后一个取出来的数,那么,最后一次的得分只与a1,an,ak有关,那么我们把整个区间以k分成两段,左边一段的最后一次得分必然为a1*ak*ai(i>1 &&i<k),也就是说左边的得分与右边怎么取无关,
那么我们总得分dp[1][n]=dp[1][k]+dp[k][n]+a[1]*a[k]*a[n];
于是我们可以得出递归方程dp[i][j]=dp[i][k]+dp[k][i]+a[i]*a[k]*a[j]. 这个方程和矩阵连乘问题的方程基本一样。那么我们可以写下如下代码
#include "iostream" using namespace std; #define len 110 int main() { int n; int a[len]; int dp[len][len];//dp[1][n]是最后结果 ,dp[i][j]=dp[i][k]+dp[k+1][j]+p*q int i,j,k; scanf("%d",&n); for (i=1;i<=n;i++) { scanf("%d",&a[i]); } //递归公式 dp[i][j]=min{dp[i][k]+dp[k+1][j]+k*i*j,k>=i k<j} for (i=1;i<=n;i++) { memset(dp[i],0,sizeof(dp[i])); dp[i][i+2]=a[i]*a[i+1]*a[i+2]; } for (int m=1;m<=n;m++) { for (i=1;i<=n;i++) { j=i+3+m; for (j=i+3;j<=n;j++) { int min=9999999;//注意这个数要取大点 for (k=i+1;k<j;k++) { if(min>dp[i][k]+dp[k][j]+a[k]*a[i]*a[j]) { min=dp[i][k]+dp[k][j]+a[k]*a[i]*a[j]; } } dp[i][j]=min; } } } printf("%d\n",dp[1][n]); return 0; }