动态规划(石子并归问题)
题意:
有 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);
}
输入格式