动态规划: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的最大值。