P4170 [CQOI2007] 涂色 题解
Getting Start
管理撤了没有证明的题解咳咳,试着抢一发。
现在想起来这题是当初 dp 入门的噩梦()。
题意简述
原题链接:https://www.luogu.com.cn/problem/P4170
把宽为
解题思路
看 tag 知区间 dp(doge)
刷子每次对一个区间的颜色造成影响,可以倒着考虑。
由小到大考虑每个区间,长为
对于该区间两端的颜色来说,如果这两个颜色相同,完全可以最先刷上这个颜色,从一端直接刷到该区间另一端,把两端之间的别的颜色放后面再刷,覆盖在区间上。
设
如果该区间两端的颜色不同,没法一刷子搞定。枚举断点
考虑正确性。证明不太严谨但可以意会。
两端颜色相同时比较显然,一刷到底和两端各刷一次相比,节省了一刷子的花费。
因为除了一刷到底也没有别的节省花费的方法了,两端颜色不同时,肯定至少要刷两次,同时希望区间里别的颜色花费尽量小,就枚举断点找最小花费和:还是从子问题最优推到全局最优。
代码实现
#include <bits/stdc++.h>
using namespace std;
const int maxn = 55;
string board;
int dp[maxn][maxn];
int main(){
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> board;
int n = board.size();
memset(dp, 0x3f, sizeof dp);
for(int i = 0; i < n; i ++)
dp[i][i] = 1; //这个初始化其实就是区间长为 1 的情况
for(int len = 2; len <= n; len ++) //所以直接从 2 开始了
for(int l = 0; l + len - 1 < n; l ++){
int r = l + len - 1;
if(board[l] == board[r])
dp[l][r] = min(dp[l + 1][r], dp[l][r - 1]);
else
for(int k = l; k < r; k ++)
dp[l][r] = min(dp[l][r], dp[l][k] + dp[k + 1][r]);
}
cout << dp[0][n - 1] << '\n';
return 0;
}
Ending
完结撒花。如果有解释的不到位的地方欢迎评论提出。
希望所有刚接触区间 dp 的 OIer 们都能吃透这道题。