题目描述
注:本题数据较水,
2
≤
N
≤
100
2\le N\le100
2≤N≤100
解题思路
这题一共有三种解法。第一种是先枚举边界,再枚举要合并的堆数,然后求出结果。
状态转移方程:
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
]
[
j
]
,
d
p
[
i
]
[
k
]
+
d
p
[
k
+
1
]
[
j
]
+
f
[
j
]
−
f
[
i
−
1
]
)
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+f[j]-f[i-1])
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+f[j]−f[i−1])
代码1
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int dp[105][105],x,f[101],n;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>x;
f[i]=f[i-1]+x;//前缀和
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) dp[i][j]=10000001;
for(int i=1;i<=n;i++) dp[i][i]=0;
for(int i=n-1;i>=1;i--)//枚举第i堆石子
for(int j=i+1;j<=n;j++)//枚举要和第i堆石子合并的石子
for(int k=i;k<=j-1;k++)//枚举分割线
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+f[j]-f[i-1]);//f[j]-f[i-1]为合并第i堆到第j堆石子的得分
cout<<dp[1][n];//输出合并第1堆到第n堆石子的得分
return 0;
}
第二种解法是先枚举要合并的堆数,再枚举边界,再求出结果。
状态转移方程:
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
]
[
j
]
,
d
p
[
i
]
[
k
]
+
d
p
[
k
+
1
]
[
j
]
+
f
[
j
]
−
f
[
i
−
1
]
)
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+f[j]-f[i-1])
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+f[j]−f[i−1])
代码2
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int dp[105][105],x,f[101],n;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>x;
f[i]=f[i-1]+x;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) dp[i][j]=10000001;
for(int i=1;i<=n;i++) dp[i][i]=0;
for(int len=2;len<=n;len++)//枚举堆数
for(int i=1;i<=n-len+1;i++){//从第1堆枚举到第n-len+1堆
int j=i+len-1;
dp[i][j]=0x7fffffff;
for(int k=i;k<=j-1;k++)
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+f[j]-f[i-1]);
}
cout<<dp[1][n];
return 0;
}
第三种解法是先枚举长度,再枚举分割线。
状态转移方程:
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
]
[
j
]
,
d
p
[
i
]
[
k
]
+
d
p
[
i
+
k
]
[
j
−
k
]
+
f
[
i
+
j
−
1
]
−
f
[
i
−
1
]
)
dp[i][j]=min(dp[i][j],dp[i][k]+dp[i+k][j-k]+f[i+j-1]-f[i-1])
dp[i][j]=min(dp[i][j],dp[i][k]+dp[i+k][j−k]+f[i+j−1]−f[i−1])
代码3
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int dp[105][105],x,f[101],n;
int main(){
cin>>n;
memset(dp,127/3,sizeof(dp));
for(int i=1;i<=n;i++){
cin>>x;
f[i]=f[i-1]+x;
dp[i][1]=0;
}
for(int j=2;j<=n;j++)//依旧是枚举堆数
for(int i=1;i<=n-j+1;i++){ //枚举边界
for(int k=1;k<=j-1;k++)//枚举分割线
dp[i][j]=min(dp[i][j],dp[i][k]+dp[i+k][j-k]+f[i+j-1]-f[i-1]);
}
cout<<dp[1][n];
return 0;
}
今天的博客又氵完了