动态规划:P4170[CQOI2007]涂色 区间DP

P4170[CQOI2007]涂色

 

 思路和推导过程:

    这题也是一个区间上的DP,构建DP[i][j]表示i到j的区间变成目标需要的最少涂色次数,对于单个字母的区间,都初始化为1,因为变成目标字母只需要涂一次。

显然我们可以得出状态转移方程 有三种转移情况:
dp[l][r]=1 l==r
dp[l][r]=min(dp[l+1][r],dp[l][r-1]) s[l]==s[r]
当区间的端点颜色相同时候,我们可以看作是在l+1->r 或者 l->r-1区间上,端点值的颜色就是涂最底层
那么对于新出现的l端点或者r端点只需要在第一次涂最底层的时候多刷一格,不需要耗费额外的涂色次数
dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]) s[l]!=s[r]
端点值颜色不相同时,相当于把这个区间割成两块子区间分别涂色,涂这两块子区间的涂色数之和的最小值情况,
就是dp[l][r],涂这个大区间的最少涂色数,也就是最优解

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 = 55;
 9 string s;
10 int dp[maxn][maxn];
11 int main()
12 {
13     
14     cin >> s;
15     int n = s.length();
16     //memset(dp, 0x7fffff, sizeof(dp));memset只能初始化为0or-1or0x3f
17     memset(dp,0x3f,sizeof(dp));
18     for (int i = 0; i < n; ++i)dp[i][i] = 1;//边界条件:单个格子变成目标颜色的最小步骤为1
19     for(int len=2;len<=n;++len)
20         for (int l = 0; l + len - 1 < n; ++l)
21         {
22             int r = l + len - 1;
23             if (s[l] == s[r])
24                 dp[l][r] = min(dp[l][r - 1], dp[l + 1][r]);
25             else
26             {
27                 for (int k = l; k < r; ++k)
28                 {
29                     dp[l][r] = min(dp[l][r], dp[l][k] + dp[k + 1][r]);
30                 }
31             }
32         }
33     cout << dp[0][n-1];
34     return 0;
35 }

 

Memset:

 在这里初始化时,我还新学到了一个东西,memset用的时候的注意点,memset(dp,value,sizeof(dp)),这个value只能为0 -1 0x3f,因为memset是逐字节初始化,把每一个字节初始化为0x3f就相当于把整个数初始化为1e9多,接近Int的最大值。

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