动态规划:P3146 [USACO16OPEN]248 G

 [USACO16OPEN]248 G

 

 思路与推导过程:

    这题还是挺细节的,是一题区间dp,我们构建的dp[i][j]并不是代表i j 区间内能合成的最优值,而是代表能这个区间能完全合并为一个什么数,如果不行,这个区间的DP值仍然是一开始赋的-inf,一个巨小值。我们为什么要这么构建呢,如果构建的是区间中最大值,那么最后答案是我们常规的dp[1][n],但是这样实际上是错误的比如1 2 2 1 2 2 ,对于1->3这个区间我们认为能合并的最优值是2+1=3,4->6这个区间算出来也是2+1=3,所以我们再算1->6这个区间时我们用1->,4->6这个两个区间来合并算出来的最优值是3+1=4,但实际上这样是错的,2 2 1 2 2,2 2 就算合并了,两个3中间隔了一个1根本不能合并,所以我们为了避免出现这样的考虑,我们改变dp定义的含义,dp[][]代表这个区间能完全合并成一个数得情况,所以相邻的两个区间,只有都能完全合并成一个数,并且一样在能互相转移,如果这个区间的dp值很小,是初始化的-inf,那么说明这个区间无法完全合成一个数,就不算这个区间,然后我们定义一个ans,对于每一个区间的合出来的数,来更新ans,最后ans就是求解的答案,并非dp[1][n].

    关键DP状态转移:

 

 完整AC代码:

 1 #include<iostream>
 2 #include<cmath>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<cstring>
 6 #include<string>
 7 using namespace std;
 8 const int maxn = 300;
 9 int a[maxn];
10 int dp[maxn][maxn];
11 int read()
12 {
13     int x = 0, f = 1;
14     char ch = getchar();
15     if (ch > '9' || ch < '0')
16     {
17         f = -1;
18         ch = getchar();
19     }
20     while (ch >= '0' && ch <= '9')
21     {
22         x = (x << 3) + (x << 1) + ch - '0';
23         ch = getchar();
24     }
25     return x * f;
26 }
27 int main()
28 {
29     int n = read();
30     int ans = -0xffffff;
31     for (int i = 1; i <= n; ++i)a[i] = read(),dp[i][i]=a[i];
32     for (int len = 2; len <= n; ++len)
33     {
34         for (int l = 1; l + len - 1 <= n; ++l)
35         {
36             int r = l + len - 1;
37             for (int k = l; k < r; ++k)
38             {
39                 if (dp[l][k] == dp[k + 1][r])
40                 {
41                     dp[l][r] = max(dp[l][r], dp[l][k] + 1);
42                     ans = max(ans, dp[l][r]);
43                 }
44             }
45         }
46     }
47     cout << ans;
48     return 0;
49 
50 }

 

 

posted @ 2022-04-20 09:22  朱朱成  阅读(36)  评论(0编辑  收藏  举报