• UVA 11584 "Partitioning by Palindromes"(DP+Manacher)


    传送门

    题意  

    思路一

      定义 dp[i] 表示 0~i 的最少划分数;

      首先,用马拉车算法求解出回文半径数组;

      对于第 i 个字符 si,遍历 j (0 ≤ j < i),判断以 j 为回文中心的最大回文串是否包含 si

      如果包含,dp[ i ]=min{dp[ i ],dp[2*j-i-1]+1};

    Code

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=1e3+50;
     4 
     5 char t[maxn];
     6 int r[maxn<<1];
     7 
     8 struct Manacher
     9 {
    10     char s[maxn<<1];
    11     void Init(char *ss,int len)
    12     {
    13         int index=0;
    14         s[index++]='#';
    15         for(int i=0;i < len;++i)
    16         {
    17             s[index++]=ss[i];
    18             s[index++]='#';
    19         }
    20         s[index]='';
    21     }
    22     void mana(char *ss)
    23     {
    24         Init(ss,strlen(ss));
    25         int len=strlen(s);
    26         int R=-1;
    27         int C;
    28         for(int i=0;i < len;++i)
    29         {
    30             r[i]=R > i ? min(R-i+1,r[2*C-i]):1;
    31             for(;i-r[i] >= 0 && i+r[i] < len && s[i-r[i]] == s[i+r[i]];r[i]++);
    32             if(i+r[i] > R)
    33             {
    34                 R=i+r[i]-1;
    35                 C=i;
    36             }
    37         }
    38     }
    39 }_mana;
    40 
    41 int dp[maxn];
    42 int Solve()
    43 {
    44     _mana.mana(t);
    45 
    46     dp[0]=1;
    47     int len=strlen(t);
    48     for(int i=1;i < len;++i)
    49     {
    50         dp[i]=dp[i-1]+1;
    51         for(int j=0;j <= 2*i;++j)
    52         {
    53             
    54             ///t中的第i个字符在预处理后的s数组中的位置为2*i+1
    55             ///因为可能由偶回文的情况,所以需要用到'#'
    56             ///直接判断在s数组中j的对应的最大回文j+r[j]是否包含2*i+1
    57             ///如果包含,再找到2*i+1以j为中心的对称点2*j-(2*i+1)
    58             ///判断2*j-(2*i+1)对应于t中的位置的前一个位置(2*j-(2*i+1))/2-1是否在[0,len-1]范围内
    59             ///如果在,更新dp[i]
    60             int cur=j+r[j];
    61             int index=(2*j-2*i-1)/2-1;
    62             if(2*i+1 < cur)
    63                 dp[i]=min(dp[i],1+(index >= 0 ? dp[index]:0));
    64         }
    65     }
    66     return dp[len-1];
    67 }
    68 int main()
    69 {
    70 //    freopen("C:\Users\hyacinthLJP\Desktop\in&&out\contest","r",stdin);
    71     int test;
    72     scanf("%d",&test);
    73     while(test--)
    74     {
    75         scanf("%s",t);
    76         printf("%d
    ",Solve());
    77     }
    78     return 0;
    79 }
    View Code 

    思路二(reference from zishu)

      定义dp[ i ]表示0~i划分成的最小回文串的个数,则dp[ i ]=min{d[ j ]+1 | j ≤ i && t[ j+1,....,i ]为回文串};

    code

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=1e3+50;
     4 
     5 char t[maxn];
     6 char s[maxn<<1];
     7 bool isPal[maxn][maxn];
     8 int dp[maxn];
     9 
    10 void Init()///O(n^2)预处理出t[i,..,j]是否为回文串
    11 {
    12     int len=strlen(t);
    13     for(int i=0;i < len;++i)
    14         for(int j=0;j < len;++j)
    15             isPal[i][j]=false;
    16     int index=0;
    17     s[index++]='#';
    18     for(int i=0;i < len;++i)
    19     {
    20         s[index++]=t[i];
    21         s[index++]='#';
    22     }
    23     s[index]='';
    24 
    25     for(int i=0;i < index;++i)
    26     {
    27         int r=0;
    28         while(i-r >= 0 && i+r < index && s[i-r] == s[i+r])
    29         {
    30             if((i-r)&1)
    31                 isPal[(i-r)/2][(i+r)/2]=true;
    32             r++;
    33         }
    34     }
    35 }
    36 
    37 int Solve()
    38 {
    39     Init();
    40     int len=strlen(t);
    41     dp[0]=1;
    42     for(int i=1;i < len;i++)
    43     {
    44         dp[i]=dp[i-1]+1;
    45         for(int j=0;j < i;++j)
    46             if(isPal[j][i])
    47                 dp[i]=min(dp[i],1+(j > 0 ? dp[j-1]:0));
    48     }
    49     return dp[len-1];
    50 }
    51 int main()
    52 {
    53 //    freopen("C:\Users\hyacinthLJP\Desktop\in&&out\contest","r",stdin);
    54     int test;
    55     scanf("%d",&test);
    56     while(test--)
    57     {
    58         scanf("%s",t);
    59         printf("%d
    ",Solve());
    60     }
    61     return 0;
    62 }
    View Code
  • 相关阅读:
    [LeetCode]N-Queens
    [LeetCode]Anagrams
    [LeetCode]Permutations II
    [LeetCode]Permutations
    [STL]heap和priority_queue
    [STL]deque和stack、queue
    10、小易记单词--2017网易春招
    29、剑指offer--最小的K个数
    28、剑指offer--数组中出现次数超过一半的数字
    9、涂棋盘--2017网易春招
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/11001763.html
Copyright © 2020-2023  润新知