一、
题目:石子归并CSU - 1592
代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<set> //自动从小到大排序,且没有重复
using namespace std;
const int maxn = 100 + 5;
const int INF = 1e9;
int n;
int a[maxn];
int sum[maxn]; //记录前缀和,方便算得分
int dp[maxn][maxn];
/*
区间dp
对比题J
*/
int main(){
int t;
scanf("%d", &t);
while(t--){
scanf("%d", &n);
for(int i=1; i<=n; i++){
scanf("%d", &a[i]);
}
fill(dp[0], dp[0]+maxn*maxn, INF);
sum[0] = 0;
for(int i=1; i<=n; i++){
dp[i][i] = 0;
sum[i] = sum[i-1] + a[i];
}
//从小到大枚举区间长度
//区间[1, n]
int end;
for(int len=1; len<n; len++){ //区间长度 从1到n-1
for(int s=1; s<=n-len; s++){ //start起始下标 s+len<=n :因为len>=1,所以i最多会被枚举到 n-1
end = s+len; //结束下标 end = s+len
for(int k=s; k<=end-1; k++){ //中间点下标 k必须从s起,不然会WA
dp[s][end] = min(dp[s][end], dp[s][k] + dp[k+1][end] + sum[end] - sum[s-1]); //sum[end]-sum[s-1]是合并本次区间的得分
}
}
}
cout << dp[1][n] << endl;
}
return 0;
}
二、
题目:Multiplication Puzzle POJ - 1651
代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<set> //自动从小到大排序,且没有重复
using namespace std;
const int maxn = 100 + 5;
const int INF = 1e9;
/*
区间dp,可转化为矩阵链乘
对比题I
*/
int n;
int a[maxn];
int dp[maxn][maxn];
int main(){
scanf("%d", &n);
for(int i=0; i<n; i++){
scanf("%d", &a[i]);
}
memset(dp, 0, sizeof(dp));
for(int i=0; i+2<n; i++){
dp[i][i+2] = a[i] * a[i+1] * a[i+2]; //初始长度为2时的乘积 ,此时包含3个数
}
//对比着i题的区间dp看
//区间 [0, n-1]
int e;
for(int len=3; len<n; len++){ //长度从3开始枚举,此时包含四个数
for(int s=0; s+len<n; s++){ //起始位置
e = len + s; //终点
for(int k=s+1; k<e; k++){ //枚举断点 ,删除的不是k,而是中间除了s, k, end以外的点 ,本轮选取k
if(dp[s][e]==0) dp[s][e] = dp[s][k] + dp[k][e] + a[s] * a[k] * a[e]; //还没有被计算过
else dp[s][e] = min(dp[s][e], dp[s][k] + dp[k][e] + a[s] * a[k] * a[e]);
}
}
}
cout << dp[0][n-1] << endl;
return 0;
}
三、
题目:Zuma CodeForces - 607B
代码
#include <iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int INF = 1e9;
const int maxn = 500 + 10;
int n;
int a[maxn];
int dp[maxn][maxn];
int main(){
scanf("%d", &n);
for(int i=0; i<n; i++) scanf("%d", &a[i]);
//初始化
for(int i=0; i<n; i++){
for(int j=0; j<n; j++){
dp[i][j] = INF;
}
}
for(int i=0; i<n; i++) dp[i][i] = 1;
for(int i=0; i<n-1; i++){
if(a[i] == a[i+1]) dp[i][i+1] = 1;
else dp[i][i+1] = 2;
}
//区间[0, n-1]
int end;
for(int len=2; len<n; len++){
for(int s=0; s+len<n; s++){
end = s + len;
//按区间长度从小到大来的,这步等于缩小了区间长度,所以肯定在前面已经计算过了
if(a[s] == a[end]) dp[s][end] = dp[s+1][end-1];
for(int k=s; k<end; k++){
dp[s][end] = min(dp[s][end], dp[s][k] + dp[k+1][end]);
}
}
}
cout << dp[0][n-1] << endl;
return 0;
}