hihocoder 1320 - 压缩字符串 - [hiho一下160周]

这道题目可以说是一道非常好非常一颗赛艇的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 }

使用比较暴力的方法,并不难写,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\n",dp[1][len]);
63     }
64 }

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

时间: 07-26

hihocoder 1320 - 压缩字符串 - [hiho一下160周]的相关文章

hihoCoder #1320 : 压缩字符串 区间dp

/** 题目:hihoCoder #1320 : 压缩字符串 链接:https://hihocoder.com/problemset/problem/1320 描述 小Hi希望压缩一个只包含大写字母'A'-'Z'的字符串.他使用的方法是:如果某个子串 S 连续出现了 X 次,就用'X(S)'来表示. 例如AAAAAAAAAABABABCCD可以用10(A)2(BA)B2(C)D表示. 此外,这种压缩方法是可以嵌套的,例如HIHOHIHOCODERHIHOHIHOCODER可以表示成2(2(HIH

hihocoder 1320 压缩字符串(字符串+dp)

题解: 其实就是对应三种dp的转移方式 1.拼接类型 dp[i][j] = dp[i][c] + dp[c][j] 2.不变类型 dp[i][j] = j-i+1 3.重复类型(必须满足有k个循环节) dp[i][j] = width(k) + 2 + dp[i][i+L-1] 直接记忆化搜索即可,复杂度n^3logn(枚举循环节近似为logn) #include <iostream> #include <cstdio> #include <cstring> using

hihocoder 1323 - 回文字符串 - [hiho一下162周][区间dp]

用dp[i][j]表示把[i,j]的字符串str改写成回文串需要的最小操作步数. 并且假设所有dp[ii][jj] (ii>i , jj<j)都为已知,即包括dp[i+1][j].dp[i][j-1].dp[i+1][j-1]这三者都已知,则: 1. 如果str[i]==str[j],那么dp[i][j]=dp[i+1][j-1]: 2. 否则dp[i][j]可以分为: ①"一个字符"+"一个回文串"型:那么我们可以在str[i,j]后面加上一个字符,或

hihocoder 1330 - 数组重排 - [hiho一下167周][最小公倍数]

题目链接:https://hihocoder.com/problemset/problem/1330 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi想知道,如果他每次都按照一种固定的顺序重排数组,那么最少经过几次重排之后数组会恢复初始的顺序? 具体来讲,给定一个1 - N 的排列 P,小Hi每次重排都是把第 i 个元素放到第 Pi个位置上.例如对于 P = (2, 3, 1),假设初始数组是(1, 2, 3),重排一次之后变为(3, 1, 2),重排两次之后

hihocoder 1331 - 扩展二进制数 - [hiho一下168周]

题目链接:http://hihocoder.com/problemset/problem/1331 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 我们都知道二进制数的每一位可以是0或1.有一天小Hi突发奇想:如果允许使用数字2会发生什么事情?小Hi称其为扩展二进制数,例如(21)ii = 2 * 21 + 1 = 5, (112)ii = 1 * 22 + 1 * 21 + 2 = 8. 很快小Hi意识到在扩展二进制中,每个数的表示方法不是唯一的.例如8还可以有(

欧拉路径 提高篇 hiho第51周

题目链接:hiho 第51周 思路:首先特判n=1的情况,无输出.对于其他的按有向欧拉路径的求法把欧拉路径求出来以后,第一个按位全输出,接下来的的(2^n-1)个点,只需要输出二进制最后一位就可以了.详细的思路参考hiho 第51周 /************************************************************** Problem:hiho 第51周 User: youmi Language: C++ Result: Accepted Time:17m

欧拉路径 基础题 hiho第49周

题目链接:hiho 第49周 思路: 定义:给定无孤立结点图G,若存在一条路,经过图中每边一次且仅一次,该条路称为欧拉路. 性质:  1: 一个无向图存在欧拉路当且仅当该图是连通的且有且只有2个点的度数是奇数,此时这两个点只能作为欧拉路径的起点和终点.  2: 若图中没有奇数度的点,那么起点和终点一定是同一个点,这样的欧拉路叫做欧拉回路 利用性质做题就好了,具体的模拟hiho讲的非常清楚了 /****************************************************

图片转成二进制并且压缩字符串

今天工作需要写了一个把图片转成字符串,并且压缩的小功能,其中用到了多线程去转换字符串,感觉写的还是不错的,拿出来分享一下 1 /// <summary> 2 /// 创建多核任务 3 /// </summary> 4 /// <param name="bytimages"></param> 5 /// <param name="count">创建几个核</param> 6 public stri

华为上机练习题--压缩字符串

题目: 通过键盘输入一串小写字母(a~z)组成的字符串.请编写一个字符串压缩程序,将字符串中连续出席的重复字母进行压缩,并输出压缩后的字符串. 压缩规则: 1.仅压缩连续重复出现的字符.比如字符串"abcbc"由于无连续重复字符,压缩后的字符串还是"abcbc". 2.压缩字段的格式为"字符重复的次数+字符".例如:字符串"xxxyyyyyyz"压缩后就成为"3x6yz". 要求实现函数: void str