【每日一题】7月28日题目精讲—涂色PAINT
[CQOI2007]涂色PAINT
https://ac.nowcoder.com/acm/problem/19909
https://ac.nowcoder.com/acm/problem/19909
思路:
f[i][j]表示把i到j的区间涂好的最少次数
当i和j颜色一样——可以认为i是涂[i+1,j]的时候顺便涂上的,或者j是涂[i,j-1]的时候顺便涂上的。所以f[i][j]= min(f[i+1][j], f[i][j-1])
i和j颜色不一样:枚举断点——f[i][j]=min(f[i][j],f[i][k]+f[k+1][j])
f[i][j]表示把i到j的区间涂好的最少次数
当i和j颜色一样——可以认为i是涂[i+1,j]的时候顺便涂上的,或者j是涂[i,j-1]的时候顺便涂上的。所以f[i][j]= min(f[i+1][j], f[i][j-1])
i和j颜色不一样:枚举断点——f[i][j]=min(f[i][j],f[i][k]+f[k+1][j])
啊反正我是想不出来,dp真是老大难。。。。。。
#include<iostream> #include<string> #include<math.h> #include<algorithm> #include<bits/stdc++.h> typedef long long ll; ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; } ll lcm(ll a, ll b) { return a * b / (gcd(a, b)); } #define PII pair<int,int> using namespace std; const int N = 1e5 + 5, mod = 1e9 + 7, inf = 0x3f3f3f3f; int qmi(int a, int k, int p) //快速幂模板 { int res = 1; while (k) { if (k & 1) res = (ll)res * a % p; k >>= 1; a = (ll)a * a % p; } return res; } /////////////////////////////////////////////////////////// int dp[105][105]; int main() { char s[N]; scanf("%s", s + 1); int l = strlen(s + 1); memset(dp, inf, sizeof(dp)); for (int i = 0; i <= l; i++) dp[i][i] = 1; for (int len = 1; len <= l; len++) { for (int i = 1, j = i + len; j <= l; i++, j++) { if (s[i] == s[j]) dp[i][j] = min(dp[i + 1][j], dp[i][j - 1]); else { for (int k = i; k < j; k++) {//断点,将两个加起来 dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j]); } } } } cout << dp[1][l] << endl; return 0; }