完美串

Description

爱美之心人皆有之,GG也不例外。所以GG他对于完美串有一种热衷的爱。在GG眼中完美串是一个具有无比魅力的01子串。这个子串有之其魅力之处,对它取反后水平翻转,它又和它原来的一模一样。这就是GG热爱它的原因。但是世上并不是所有的01串都是完美串,所以GG下定决心想改造01串,使所有的01串都成为完美串。但是改造01串是一个巨大的工程,GG太忙了,他还差T个01串未改造,他需要你的帮助。而你只需要告诉它至少添加几个'0','1'字符就可以使得01串成为完美串。

Input

有T组数据输入。(T<=100) 
每组数据只有两行,第一行一个正整数n(1<=n<=1000),接下来一行是一个01字符串,长度为n。 

  

Output

对于每组数据输出一行结果

Sample Input

2 4 1001 3 111

Sample Output

2 3

HINT

分析:

首先分析字符串满足怎么样的情况,是完美串,不需要加入0和1.

设Ai = 对A取反。

则设一个字符串为 ABCDEF,转换后 应该是FiEiDiCiBiAi

Fi = A; Ei = B; Di = C; Ci = D;Bi = E; Ai = F;

所以如果是偶数字符串,而且只有0和1两个数。

所以只要满足 第一位和最后一个不同,第二位和最后第二位不同...这是长度为偶数的情况。

如果长度为奇数。显然中间那个数无论是什么都不成立。所以奇数肯定需要加0,1的。

再设dp[i][j]为第i位到第j位最少需要加0,1的个数。

由上面可以知道 dp[i][i]即 只有一位的时候,肯定需要再加一位和这位相反的数才可以,所以dp[i][i] = 1

只有2位的情况,由上面的规律可以知道 如果这两位不相等,那么不用添加 dp[i][i+1] = 0;如果相等,那么至少要加两个数 所以dp[i][i+1] = 2

现在考虑2位以上的情况。

由上面的规律可以推得 如果s[i] != s[j] 那么dp[i][j] = dp[i+1][j-1].

如何更新dp[i][j]的最小值呢?

一开始想的是枚举k 取dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j]).

但是由第一组样例发现是不成立的,因为比如说1001 当i = 0, j = 3 当k = 1的时候,10和01,计算出的最小值都为0,但是组成的1001答案并不为0

因为两个字符串为完美串的时候 组成的不一定为完美串。

再考虑如果一个串是完美串,则如果再加一位在它的最后,有可能组成了完美串,也有可能变成非完美串,如果变成非完美串,则在字符串的最前面再加一位和最后一位不同的数就行了。

加在最后也一样。

所以又可以推得dp[i][j] = min(dp[i][j], dp[i][j-1]+1)

       dp[i][j] = min(dp[i][j], dp[i+1][j]).

刚学习区间DP,写的详细一点。

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <string>
 5 #include <algorithm>
 6 using namespace std;
 7 int T, n;
 8 #define maxn 1010
 9 #define INF 9999999
10 int dp[maxn][maxn];
11 //dp[i][j]表示从第i位到第j位最少要添加的0,1数 
12 int main(){
13     scanf("%d", &T);
14     while(T--){
15         scanf("%d", &n);
16         string s; cin>>s;
17         for(int i = 0; i < s.size(); i++){
18             for(int j = 0; j < s.size(); j++) dp[i][j] = INF;
19         }
20         for(int i = 0; i < s.size(); i++) dp[i][i] = 1; //如果是1位 肯定需要添加一个0或1
21         for(int i = 0; i < s.size()-1; i++){     //两位的情况 
22             if(s[i] != s[i+1]) dp[i][i+1] = 0;  //如果不相等 不用添加,满足条件 
23             else dp[i][i+1] = 2;                //如果相等的话,理想就是中间添加一位,这样就满足了 
24         }
25         for(int len = 2; len < s.size(); len++){
26             for(int i = 0, j = len; j < s.size(); i++,j++){
27                 if(s[i] != s[j]){
28                     dp[i][j] = min(dp[i][j],dp[i+1][j-1]);
29                 }
30                 dp[i][j] = min(dp[i][j], dp[i+1][j]+1);
31                 dp[i][j] = min(dp[i][j], dp[i][j-1]+1);
32                 
33             }
34         } 
35         printf("%d
",dp[0][s.size()-1]);
36     }
37     return 0;
38 }
原文地址:https://www.cnblogs.com/titicia/p/4345613.html