Input
第1行:N(2 <= N <= 100) 第2 - N + 1:N堆石子的数量(1 <= Aii <= 10000)
Output
输出最小合并代价
Sample Input
4 1 2 3 4
Sample Output
19
虽然知道这是一道dp题目,但是刚开始的时候怎么也想不出怎么做状态转移,于是又是blog和csdn一顿搜,终于搞出来了。
我们设dp[i][j]是从第i堆石子到第j堆石子合并的最小代价,sum[i]是前i堆石子的数量之和,那么状态转移方程就是:
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1])
就是把第i堆到第j堆石子分成第i堆到第k堆石子、第k+1堆到第j堆石子,再加上这两大堆石子合并(sum[j]-sum[i-1]),在i<=k<j的范围遍历,找到最小值即可。
由于d[i][j]依赖于d[i][k]和d[k+1][j],所以我们要根据len(j-i)的大小从小到大来循环,这样才能每次都能确保d[i][j]分解的d[i][k]和d[k+1][j]在这之前计算过。
具体细节看代码:
1 #include<iostream>
2 #include<cstring>
3 using namespace std;
4 #define inf 0x3f3f3f3f
5 const int maxn=101;
6 int n,a[maxn],dp[maxn][maxn],sum[maxn];
7 int main()
8 {
9 while(cin>>n)
10 {
11
12 for(int i=1;i<=n;i++)
13 {
14 cin>>a[i];
15 sum[i]=sum[i-1]+a[i];
16 }
17 for(int i=1;i<=n;i++)
18 {
19 for(int j=1;j<=n;j++)
20 {
21 dp[i][j]=i==j?0:inf;
22 }
23 }
24 for(int len=1;len<n;len++)
25 {
26 for(int i=1;i+len<=n;i++)
27 {
28 int j=i+len;
29 for(int k=i;k<j;k++)
30 {
31 dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
32 }
33 }
34 }
35 cout<<dp[1][n]<<endl;
36 }
37 }
如果石堆摆成环状呢?
思路就是把它拆成直线型的,比如说题目的1234,我们把它拆成线性的以后就是1234123,然后在从这里找出合并相邻的4堆石子的最小代价就行了,做法跟原来的差不多,不过最后再搜一个最小值,洛谷1880就有这道题,不过洛谷的题还要求最大代价,这是我a了洛谷的代码:
1 #include<iostream>
2 #include<cstring>
3 #define inf 0x3f3f3f3f
4 using namespace std;
5 const int maxn=2e3+5;
6 int n,a[maxn],dp_min[maxn][1001],dp_max[maxn][1001],sum[maxn],s=inf;
7 int main()
8 {
9 cin>>n;
10 for(int i=1;i<=n;i++)
11 {
12 cin>>a[i];
13 sum[i]=sum[i-1]+a[i];
14 }
15 for(int i=n+1;i<=n*2-1;i++)
16 {
17 a[i]=a[i-n];
18 sum[i]=sum[i-1]+a[i];
19 }
20 for(int len=1;len<n;len++)
21 {
22 for(int i=1;i+len<=2*n;i++)
23 {
24 int j=i+len;
25 dp_min[i][j]=inf;
26 for(int k=i;k<j;k++)
27 {
28 dp_min[i][j]=min(dp_min[i][j],dp_min[i][k]+dp_min[k+1][j]+sum[j]-sum[i-1]);
29 dp_max[i][j]=max(dp_max[i][j],dp_max[i][k]+dp_max[k+1][j]+sum[j]-sum[i-1]);
30 }
31 }
32 }
33 int ans_min=inf,ans_max=0;
34 for(int i=1;i<=n;i++)
35 {
36 ans_min=min(ans_min,dp_min[i][i+n-1]);
37 ans_max=max(ans_max,dp_max[i][i+n-1]);
38 }
39 cout<<ans_min<<endl<<ans_max<<endl;
40 }
为什么跑到洛谷去a题了?因为这个做法在这道题会T啊<(_ _)>,O(n^3)的算法,n又是1000,难顶。
不过还好,既然有这道题,一定就有解法。在网上查了一通,说是要用什么四边形不等式优化成O(n^2),看的我真的脑壳疼。
不学会怎么行?不过我就算懂了一些,也表达不出来,给你们推荐这个大佬的blog:https://www.cnblogs.com/cglongge/p/9451161.html
来源:https://www.cnblogs.com/hailin545/p/12264451.html