石子归并

Posted wsy107316

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了石子归并相关的知识,希望对你有一定的参考价值。

技术图片

 

 技术图片

 

 

【思路】

 我们 dp[i][j] 来表示合并第 i 堆到第 j 堆石子的最小代价。

 那么状态转移方程为  dp[i][j] = min ( dp[i][j],dp[i][k]+dp[k+1][j]+w[i][j]);

其中, w[i][j] 表示把两部分合并起来的代价,即从第 i 堆到第 j 堆石子个数的和,为了方便查询,我们可以用 sum[i] 表示从第1堆到第i堆的石子个数和,那么 w[i][j]=sum[j]-sum[i-1].(前缀和思想)

AC_Code:

 1 #include <bits/stdc++.h>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <string>
 5 #include <cmath>
 6 #include <queue>
 7 #include <stack>
 8 #include <vector>
 9 #include <set>
10 #include <map>
11 #include <algorithm>
12 using namespace std;
13 typedef long long ll;
14 const int maxn=205;
15 const ll mod=1e9+7;
16 const ll INF=1e18;
17 const double eps = 1e-9;
18 
19 int n,x;
20 int sum[maxn];
21 int dp[maxn][maxn];///合并第i堆到第j堆石子的最小代价
22 int main()
23 {
24     while(~scanf("%d",&n)){
25         sum[0]=0;
26         memset(dp,0x3f,sizeof(dp));
27         for(int i=1;i<=n;i++){
28             scanf("%d",&x);
29             sum[i]=sum[i-1]+x;
30             dp[i][i]=0;
31         }
32         for(int len=2;len<=n;len++){
33             for(int i=1;i<=n;i++){
34                 int j=i+len-1;
35                 if( j>n ) continue;
36                 for(int k=i;k<j;k++){
37                     dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+(sum[j]-sum[i-1]));
38                 }
39             }
40         }
41         printf("%d
",dp[1][n]);
42     }
43     return 0;
44 }

平行四边形优化】:详解

 1 #include <bits/stdc++.h>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <string>
 5 #include <cmath>
 6 #include <queue>
 7 #include <stack>
 8 #include <vector>
 9 #include <set>
10 #include <map>
11 #include <algorithm>
12 using namespace std;
13 typedef long long ll;
14 const int maxn=205;
15 const ll mod=1e9+7;
16 const ll INF=1e18;
17 const double eps = 1e-9;
18 
19 int n,x;
20 int sum[maxn];
21 int dp[maxn][maxn];///合并第i堆到第j堆石子的最小代价
22 int s[maxn][maxn];
23 int main()
24 {
25     while(~scanf("%d",&n)){
26         sum[0]=0;
27         memset(dp,0x3f,sizeof(dp));
28         for(int i=1;i<=n;i++){
29             scanf("%d",&x);
30             sum[i]=sum[i-1]+x;
31             dp[i][i]=0;
32             s[i][i]=i;
33         }
34         for(int len=2;len<=n;len++){
35             for(int i=1;i<=n;i++){
36                 int j=i+len-1;
37                 if( j>n ){
38                     continue;
39                 }
40                 for(int k=s[i][j-1];k<=s[i+1][j];k++){
41                     if( dp[i][k]+dp[k+1][j]+(sum[j]-sum[i-1])<dp[i][j] ){
42                         dp[i][j]=dp[i][k]+dp[k+1][j]+(sum[j]-sum[i-1]);
43                         s[i][j]=k;
44                     }
45                 }
46             }
47         }
48         printf("%d
",dp[1][n]);
49     }
50     return 0;
51 }

 

以上是关于石子归并的主要内容,如果未能解决你的问题,请参考以下文章

1048 石子归并

1048 石子归并

codevs 1048石子归并

51Nod - 1021 石子归并

线状DP(石子归并)

石子合并