难点:找到状态表示的方法
eg1:石子合并
/*
DP
一、状态表示:
1、集合 :所有将[i,j]合并成一堆的方案的集合
2、属性 :min
二、状态计算:
*/
#include<iostream>
using namespace std;
const int N=310;
int n;
int s[N];//前缀和
int f[N][N];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>s[i];
s[i]+=s[i-1];
}
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
f[i][j]=1e8;
for(int k=i;k<j;k++){
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+s[j]-s[i-1]);
}
}
}
cout<<f[1][n]<<endl;
return 0;
}
eg2:数字三角形
/*
从倒数第二行开始逆推,左下数字的最大路径和和右下数字
的最大路径和谁大就加谁。
*/
#include<iostream>
using namespace std;
const int N=105;
int main(){
int n,a[N][N],dp[N][N];//dp[i][j]为状态,意思是a[i][j]到最后一行的最大路径和
cin>>n;
int i,j;
for(i=1;i<=n;i++){
for(j=1;j<=i;j++){
cin>>a[i][j];
}
}
for(int j=1;j<=n;j++){
dp[n][j]=a[n][j];//初始化
}
for(int i=n-1;i>=1;i--){
for(int j=1;j<=i;j++){
dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+a[i][j];//状态转移方程
}
}
cout<<dp[1][1];
return 0;
}