动态规划(石子并归问题)
题意:
有 n 个石子,把n 堆石子合并成一个,合并时候只能是相邻的两个石子,合并时能获得积分为合并两队石子的数目之和,问如何合并能或得最多或者最小的积分:
例如:4 个石子
输入:4 4 5 9 (为每一堆的石子个数,如果想让1 2 堆合并则得到积分 8)
输出 43 54
解题思路:
令f[i:j] 表示把第i 堆到 到第 j 堆合并得到的积分这有
f[i:j]={ f[i:k]+f[k+1][j]} (其中 k>=i k<j)
令max[i:j] 为表示把第i 堆到 到第 j 堆合并得到的积分最大值(或者最小值)有:
max[i:j]=max{ f[i:j]+max[i:k]+max[k+1:j];
其实这这类型的题目和矩阵相乘、能量项链的题目都是类似的
#include<iostream>
#define Max 100
using namespace std;
int a[Max];
int p[Max][Max];//记录f[i:j]
int max[Max][Max];//
int s[Max][Max];// 记录为
void sovle_max(int n){//
memset(p,0,sizeof(p));
memset(max,0,sizeof(max));
for(int i=1;i<=n;i++){
p[i][i]=a[i];
}
for( int r=2;r<=n;r++){
for(int i=1;i<=n-r+1;i++){
int j=i+r-1;
int temp=0;
for(int k=i;k<j;k++){
if(p[i][k]+p[k+1][j]+max[i][k]+max[k+1][j]>temp){
temp=p[i][k]+p[k+1][j]+max[i][k]+max[k+1][j];
p[i][j]=p[i][k]+p[k+1][j];
s[i][j]=k;
}
}
//p[i][j]=temp;
max[i][j]=temp;
}
}
}
void sovle_min(int n){//
memset(p,0,sizeof(p));
memset(max,0,sizeof(max));
for(int i=1;i<=n;i++){
p[i][i]=a[i];
}
for( int r=2;r<=n;r++){
for(int i=1;i<=n-r+1;i++){
int j=i+r-1;
int temp=(1<<30);
for(int k=i;k<j;k++){
if(p[i][k]+p[k+1][j]+max[i][k]+max[k+1][j]<temp){
temp=p[i][k]+p[k+1][j]+max[i][k]+max[k+1][j];
p[i][j]=p[i][k]+p[k+1][j];
s[i][j]=k;
}
}
//p[i][j]=temp;
max[i][j]=temp;
}
}
}
void print(int n){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cout<<max[i][j]<<" ";
}
cout<<endl;
}
}
int main(void){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sovle_max(n);
print(n);
sovle_min(n);
print(n);
}
输入格式
接

本文整理了几个经典的动态规划问题,包括石子并归问题、滑雪问题以及最长公共子序列问题。通过分析题意、输入输出格式和解题思路,帮助读者理解和掌握动态规划的应用。
&spm=1001.2101.3001.5002&articleId=7955383&d=1&t=3&u=2754de3ee405446990409d29a44e42b2)
9701

被折叠的 条评论
为什么被折叠?



