zoukankan      html  css  js  c++  java
  • 完美串

    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 }
  • 相关阅读:
    bash 设置
    fabric-ca-client
    fabric工具
    nodejs
    Hyperledger 项目
    JAVA集合小结
    java内部类的作用分析
    如何使用javadoc
    30天轻松学习javaweb_Eclipse在修改了web.xml后将自动更新到tomcat服务器中
    30天轻松学习javaweb_修改tomcat的servlet模板
  • 原文地址:https://www.cnblogs.com/titicia/p/4345613.html
Copyright © 2011-2022 走看看