• hihocoder 1320


    这道题目可以说是一道非常好非常一颗赛艇的DP题了。

    需要注意的是,其中情形3),字符串必然能完全转化为 N(str)形式,如果有N(str1)M(str2)等等另外样式,应该首先使用拼接形式对其进行划分。

    那么,我们首先考虑写一个用来压缩情形3)下的字符串的函数zip():

     1 char str[105];
     2 int bit(int n)
     3 {
     4     int cnt=0;
     5     while(n>0)
     6     {
     7         n/=10;
     8         cnt++;
     9     }
    10     return cnt;
    11 }
    12 int zip(int l,int r)
    13 {
    14     int len=r-l+1;
    15     bool flag;
    16     if(len<=4) return len;
    17     for(int sec=1;sec<len;sec++)//循环节长度
    18     {
    19         if(len%sec) continue;//不能完全转化为N(str)形式 
    20         flag=1;
    21         for(int p=1;p<=sec;p++)//遍历循环节中的每个结点 
    22         {
    23             char now=str[l+p-1];
    24             for(int i=l+sec;i<=r;i+=sec)//遍历每个循环节的头结点 
    25             {
    26                 if(str[i+p-1]!=now)
    27                 {
    28                     flag=0;
    29                     break;
    30                 } 
    31             } 
    32             if(!flag) break;
    33         }
    34         if(flag) return(bit(len/sec) + 2 + sec);//如果字符串可以按这个循环节进行压缩 
    35     }
    36     return len;
    37 }
    View Code

    使用比较暴力的方法,并不难写,bit()函数返回一个数字是几位数。

    既然有了zip()函数,那么就可以进一步考虑状态转移方程了,如下:

    dp[i][j]  =  min(  j - i + 1  ,  dp[i][k] + dp[k+1][j]  ,  zip( i , j )  ); (即情形1) 2) 3)中选取最小的)

    其中,dp[i][j]表示字符串str[i,j]的压缩后最短长度。

    最后,我们考虑如何进行状态转移,联想到之前http://www.cnblogs.com/dilthey/p/6889141.html中的归并思路,

    我们也可以对本题进行一定的归并,首先初始化所有dp[i][i]=1,然后,依次计算出j - i = 1,2,3,……,n-1的dp[i][j],

    另外要注意的是,我们要对zip()函数做一点小修改,如果不修改的话,样例都过不了嗷

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define INF 0x3f3f3f3f
     5 using namespace std;
     6 char str[105];
     7 int dp[105][105];
     8 int bit(int n)
     9 {
    10     int cnt=0;
    11     while(n>0)
    12     {
    13         n/=10;
    14         cnt++;
    15     }
    16     return cnt;
    17 }
    18 int zip(int l,int r)
    19 {
    20     int len=r-l+1;
    21     bool flag;
    22     if(len<=4) return len;
    23     for(int sec=1;sec<len;sec++)//循环节长度
    24     {
    25         if(len%sec) continue;//不能完全转化为N(str)形式 
    26         flag=1;
    27         for(int p=1;p<=sec;p++)//遍历循环节中的每个结点 
    28         {
    29             char now=str[l+p-1];
    30             for(int i=l+sec;i<=r;i+=sec)//遍历每个循环节的头结点 
    31             {
    32                 if(str[i+p-1]!=now)
    33                 {
    34                     flag=0;
    35                     break;
    36                 } 
    37             } 
    38             if(!flag) break;
    39         }
    40         if(flag) return(bit(len/sec) + 2 + dp[l][l+sec-1]);//如果字符串可以按这个循环节进行压缩 
    41     }
    42     return len;
    43 }
    44 int main()
    45 {
    46     int t;
    47     scanf("%d",&t);
    48     while(t--)
    49     {
    50         scanf("%s",str+1);
    51         int len=strlen(str+1);
    52         for(int i=1;i<=len;i++) dp[i][i]=1;
    53         for(int l=2;l<=len;l++) 
    54         {
    55             for(int i=1,j=i+l-1;j<=len;i++,j=i+l-1)
    56             {
    57                 int tmp=INF;
    58                 for(int k=i;k<j;k++) if(tmp>dp[i][k]+dp[k+1][j]) tmp=dp[i][k]+dp[k+1][j];
    59                 dp[i][j]=min( min(l,tmp) ,zip(i,j) );
    60             } 
    61         }
    62         printf("%d
    ",dp[1][len]);
    63     } 
    64 }

    当然,这不是一种很优化的算法,时间复杂度大概在O(len^3),可以考虑进行一定的优化。不过反正我是想不出

  • 相关阅读:
    Linux C Socket编程原理及简单实例
    clock_gettime 用法
    Linux未来监控tracing框架——eBPF
    eBPF监控工具bcc系列五工具funccount
    【转】如何测量电源纹波?
    【转】在网页中运行VB6程序
    如何为互阻抗放大器电路选择具有足够带宽的运算放大器
    互阻放大器的稳定工作及其评估
    【原创】OPA857 TEST模式使用
    [转]What you need to know about transimpedance amplifiers – part 1
  • 原文地址:https://www.cnblogs.com/dilthey/p/7252261.html
Copyright © 2020-2023  润新知