题意:
给定目标字符串状态,现给定一个空字符串,你每次可以对一区间进行染色,求最少染色次数。
分析:
染色问题首先想到dp,区间染色,我们定义 dp[i][j] 是区间 i 到区间 j 最小的涂色次数,那么答案就是 dp[1][n]。
区间dp求解是由小区间合并成大区间的,也就是我们要从长度最短的区间开始解决子问题,当区间长度为1时,我们不难得出其最小涂色次数为1,当区间长度大于时,最小染色次数为 左区间最小次数+右区间最小次数,因此我们需要枚举该区间每个断点所得到的最小染色次数最小值。特别的,当a[i] ==a[j] 时,可以由min(dp[i][j-1],dp[i+1][j])进行转移过来,因为涂一次可以涂一整个区间,l或者r的那一次染色可以拿来帮助另一个染色。
综上所述:
1. 当i==j时:dp[i][j]=1;
2. 当i!=j且a[i]==a[j]时:dp[i][j]=min(dp[i][j-1],dp[i+1][j])
3. 当i!=j且a[i]!=a[j]时:我们就需要枚举断电k ,dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j])
代码:
#include<iostream> #include<algorithm> #include<stdio.h> #include<cstring> using namespace std; #define mem(a, x) memset(a, x, sizeof(a)) typedef long long ll; void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); } const int inf=0x3f3f3f3f; string a; int dp[110][110]; int main() { cin>>a; mem(dp,0x3f3f3f); int n = a.size(); a = ' ' + a; for(int i = 1;i <= n;i++){ for(int j = 1;j + i - 1 <= n;j++){//枚举左端点 int r = j + i - 1;//k为右端点 if(r == j){ dp[j][r] = 1; continue; } if(a[j] == a[r]) dp[j][r] = min(dp[j+1][r],dp[j][r-1]); else{ for(int k = 1;k < r;k++){//枚举断点 dp[j][r] = min(dp[j][k]+dp[k+1][r],dp[j][r]); } } } } cout<<dp[1][n]<<endl; }