hdu 2476 区间dp + 普通dp

题意:

长度都为n的字符串s1和s2,每次刷颜色可将一段区间内的字符染成相同的字符,问把s1刷成s2需要的最小次数。1 <= n <= 100。

题解:

1.dp[i][j]表示把空白字符串的[i , j]染成s2的[i , j]需要的最小次数

2.初始化dp[i][i] 和 dp[i][i + 1]。

3.区间dp常把i看作特殊点,先认为i需要涂一下,dp[i][j] = dp[i + 1][j] + 1。然后遍历[i , j]内的断点,若s2[i] = s2[k],那么可以涂k的时候把i给涂掉。dp[i][j] = min(dp[i][j] , dp[i + 1][k] + dp[k + 1][j])

4.因为s1的串和s2的串可能部分相同,会比空白字符串染成s2更快,初始化ans为dp[1]。ans[i]表示把s1的[1 , i]涂成s2的[1 , i]需要的最小次数。假如s1[i] = s2[i],则ans[i] = ans[i - 1]。若不同,则在[1,i)寻找断点,ans[i] = min(ans[i] , ans[j] + dp[j + 1][i])

#include <bits/stdc++.h>
#define N 105
#define inf 0x3f3f3f3f
using namespace std;
int dp[N][N] ;
int ans[N] ;
int main()
{
    char s1[N] , s2[N] ;
    int len ;
    int i , j , k , d ;
    while(scanf("%s%s" , s1 + 1 , s2 + 1) != EOF)
    {
        len = strlen(s2 + 1);
        for(i = 1 ; i <= len ; i ++)
            dp[i][i] = 1 ;
        for(i = 1 ; i <= len - 1 ; i ++)
            dp[i][i + 1] = 1 + (s2[i] != s2[i + 1]) ;
        for(d = 2 ; d <= len - 1 ; d ++)
            for(i = 1 ; i + d <= len ; i ++)
            {
               j = i + d ;
               dp[i][j] = dp[i + 1][j] + 1 ;
               for(k = i + 1 ; k <= j ; k ++)
                 if(s2[i] == s2[k])
                   dp[i][j] = min(dp[i][j] , dp[i + 1][k] + dp[k + 1][j]) ;
            }
        for(i = 1 ; i <= len ; i ++)
            ans[i] = dp[1][i] ;
        ans[0] = 0 ;
        for(i = 1 ; i <= len ; i ++)
           if(s1[i] == s2[i])
             ans[i] = ans[i - 1] ;
           else
             for(j = 1 ; j < i ; j ++)
                ans[i] = min(ans[i] , ans[j] + dp[j + 1][i]) ;
        printf("%d\n" , ans[len]) ;
    }
}

.

猜你喜欢

转载自blog.csdn.net/Irving0323/article/details/87979484