poj 1651
http://acm.pku.edu.cn/JudgeOnline/problem?id=1651
分析来自:
http://www.tkz.org.ru/2009-10/poj-1651-multiplication-puzzle/
分析:
本来以为是矩阵连乘,谁知道不是。
以下内容来自POJ讨论版。
对于整个牌的序列,最左端和最右端的牌是不能被取走的,除这两张以外的所有牌
,必然有一张最后取走。取走这最后一张牌有一个仅与它本身以及最左端和最右端的
牌的值有关的得分,这个分值与其他牌没有任何关系。当这张最后被取走的牌被定
下来以后(假设位置为j), 最左端到j之间的所有牌被取走时所造成的得分必然只与
这之间的牌有关从而与j到最右端之间的牌独立开来。这样就构成了两个独立的子
区间,出现重叠子问题。于是问题的解就是
取走最后一张牌的得分+两个子区间上的最小得分
不妨假设当前区间为[b, e],在(b,e)之间枚举最后一张被取走的牌,通过最优子问题
求出当前区间的最优解:
opt[b][e] = min{ opt[b][j]+opt[j][e] + val(b,j,e); };
b+1<= j <=e-1
val(b,j,e)是取走j所造成的得分,即第b,j,e这三张牌的积。
空间o(n^2), 时间o(n^3)
#include<stdio.h> #include<string.h> #include <iostream> //用 INT_MAX 要此头文件 int point[100], dp[100][100]; int DP(int left, int right) { int i, min, l, r, temp; if(-1 != dp[left][right]) return dp[left][right]; if(right-left == 1) return dp[left][right] = 0; min = INT_MAX; for(i=left+1; i<right; i++) { l = DP(left, i); r = DP(i, right); temp = l + r + point[left] * point[i] * point[right]; if(min > temp) min = temp; } return dp[left][right] = min; } int main() { int nCard, i; while(scanf("%d", &nCard) != EOF) { memset(dp,-1,sizeof(dp)); //赋值-1 for(i=0; i<nCard; i++) scanf("%d", &point[i]); //忘记 & ; printf("%d\n", DP(0, nCard-1)); //右参数不是nCard } return 0; }
/**************************************************************************
                 
原文来自博客园——Submarinex的博客: www.cnblogs.com/submarinex/               
 
*************************************************************************/