51nod 1021 石子归并 1022v2 石子归并

1021 石子归并

 
N堆石子摆成一条线。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价。计算将N堆石子合并成一堆的最小代价。
 
例如: 1 2 3 4,有不少合并方法
1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19)
1 2 3 4 => 1 5 4(5) => 1 9(14) => 10(24)
1 2 3 4 => 1 2 7(7) => 3 7(10) => 10(20)
 
括号里面为总代价可以看出,第一种方法的代价最低,现在给出n堆石子的数量,计算最小合并代价。
 

输入

第1行:N(2 <= N <= 100)
第2 - N + 1:N堆石子的数量(1 <= A[i] <= 10000)

输出

输出最小合并代价

输入样例

4
1
2
3
4

输出样例

19

思路:区间DP入门题,为了后面那题热热手。 转移方程:dp[st][ed]=min(dfs(st,i)+dfs(i+1,ed)+s[ed]-s[st-1],dp[st][ed]),为了方便理解,用记忆化搜索写
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 int n,a[105],s[105],dp[105][150];
 6 int dfs(int st,int ed){
 7     if (dp[st][ed]!=-1) return dp[st][ed];
 8     if (ed<=st+1) {
 9         if (ed==st+1) return a[ed]+a[st];
10         else return 0;
11     }
12     dp[st][ed]=1000000000;
13     for (int i=st+1; i<ed; i++){
14         dp[st][ed]=min(dfs(st,i)+dfs(i+1,ed)+s[ed]-s[st-1],dp[st][ed]);
15         dp[st][ed]=min(dfs(st,i-1)+dfs(i,ed)+s[ed]-s[st-1],dp[st][ed]);
16     }
17     return dp[st][ed];
18 }
19 int main(){
20     scanf("%d",&n);
21     s[0]=0;
22     memset(dp,-1,sizeof(dp));
23     for (int i=1; i<=n; i++){
24         scanf("%d",&a[i]);
25         s[i]=s[i-1]+a[i];
26     }
27     printf("%d",dfs(1,n));
28     return 0;
29 }
View Code

 

 

1022 石子归并 V2

N堆石子摆成一个环。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价。计算将N堆石子合并成一堆的最小代价。
 
例如: 1 2 3 4,有不少合并方法
1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19)
1 2 3 4 => 1 5 4(5) => 1 9(14) => 10(24)
1 2 3 4 => 1 2 7(7) => 3 7(10) => 10(20)
 
括号里面为总代价可以看出,第一种方法的代价最低,现在给出n堆石子的数量,计算最小合并代价。
 

输入

第1行:N(2 <= N <= 1000)
第2 - N + 1:N堆石子的数量(1 <= A[i] <= 10000)

输出

输出最小合并代价

输入样例

4
1
2
3
4

输出样例

19

原网址:http://www.51nod.com/Challenge/Problem.html#problemId=1022
 
思路:其实就是普通的石子归并,但是由于数据变大,所以要用四边形不等式优化一下
 
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cstdlib>
 6 using namespace std;
 7 const int N=2009;
 8 int n,f[N][N]={0},a[N][N]={0};
 9 int s[N][N];
10 int main(){  
11     memset(f,1,sizeof(f));
12     scanf("%d",&n);
13     for(int i=0; i<n; i++){
14         scanf("%d",&a[i][i]);
15         a[n+i][n+i]=a[i][i];
16     }
17     for(int i=0; i<n*2; i++){
18         s[i][i] = i;
19         f[i][i] = 0;
20     }
21     for(int i=0; i<n*2-1; i++)
22         for(int j=i+1; j<n*2-1; j++)
23           a[i][j]=a[i][j-1]+a[j][j];
24     for(int l=1; l<n; l++){
25         for(int i=0; i+l<n*2-1; i++){
26             int j=i+l;
27             for(int k=s[i][j-1]; k<=s[i+1][j]; k++){
28                 if(f[i][j]>a[i][j]+f[i][k]+f[k+1][j]){
29                     f[i][j]=a[i][j]+f[i][k]+f[k+1][j];
30                     s[i][j]=k;
31                 }
32             }
33         }
34     }
35     int ans=f[0][n-1];
36     for(int i=1; i<n; i++)
37         if(ans>f[i][i+n-1])
38             ans=f[i][i+n-1];
39     printf("%d\n",ans);
40     return 0;
41 }
View Code

 

posted @ 2020-10-04 00:53  我是菜狗QAQ  阅读(124)  评论(0编辑  收藏  举报