SCOI 2007 压缩 C++
来源:互联网 发布:刷单平台 php源码 编辑:程序博客网 时间:2024/06/12 21:37
原题:Time Limit: 1 Sec Memory Limit: 128 MB
Description
给一个由小写字母组成的字符串,我们可以用一种简单的方法来压缩其中的重复信息。压缩后的字符串除了小写字母外可以(但不必)包含大写字母R与M,其中M标记重复串的开始,R重复从上一个M(如果当前位置左边没有M,则从串的开始算起)开始的解压结果(称为缓冲串)。 bcdcdcdcd可以压缩为bMcdRR,下面是解压缩的过程
另一个例子是abcabcdabcabcdxyxyz可以被压缩为abcRdRMxyRz。
Input
输入仅一行,包含待压缩字符串,仅包含小写字母,长度为n。
Output
输出仅一行,即压缩后字符串的最短长度。
Sample Input 1
aaaaaaa
Sample Output 1
5
Sample Input 2
bcdcdcdcdxcdcdcdcd
Sample Output 2
12
HINT
在第一个例子中,解为aaaRa,在第二个例子中,解为bMcdRRxMcdRR。
【限制】
100%的数据满足:1<=n<=50 100%的数据满足:1<=n<=50
在此声明一下,我承认参考了其他人的相关文章,但也加入了自己的理解等。如有雷同请不要见怪。
首先讲讲解题思路吧:
设整个字符串长度为n。根据题意,我们可以看作在区间[1,n]之前已经放有一个字母M。那么我们就是要用一些M和R,将字符串中的重复串分割出来,并使最终压缩后的字符串尽量短,Begin都说了这是个区间DP了对吧。在例子bcdcdcdcdxcdcdcdcd中,cd我称之为重复串,而其中的cdcdcdcd便是题目所说的缓冲串。
个人认为呢,解题的关键便是重复串和缓冲串的寻找,由此将解题方向指向对M、R位置的寻找。所以我们仅仅需要用动态规划求出M的位置就离成功不远了。如果发现当前处理的字符串中不含M,并且左右两半是一样的,那么就在中点处放一个R并去掉后面那一半就行了。比如:cdcd>>cdRcd>>cdR
然后我们就可以定义数组f[left][right][ok],用f来表示输入中left到right的部分字符串,如果ok=1则表示该部分字符串中有放M,若ok=0则反之。
现在来考虑考虑边界情况:
首先来#define INF 0x3f3f3f3f 弄个大数字吧(别问我为什么hhhhh)
边界条件是f[][][0]=1(只有一个字符不能放M呢,不然就更大了。你看b还要压缩吗),f[][][1]=INF
这边界条件怎么出来的应该一个个自己想一会都想得出吧......
我懒就懒得解释了......再说了你们那么聪明肯定会懂的对吧!
那么现在对于left到right的部分开始做处理:
如果该部分内放了M,那么我们就暴力枚举出其中一个M放在哪里,并用分割后的两个部分的状态做转移。
若该部分内没放M,我们先判断这个区间是否是一个缓冲串(左右两半的字符串一样),
如果是的话那么这个部分只需要左半部分压缩后的长度再加上一个R就够了。
不然我们就枚举R放在哪里,这样这个R就和前面最近的那个M对应起来,分割出来了一个重复串部分,
然后再用这个重复串部分的函数值做转移,R后面保持不变。
最后print出一个最小值就OK了。
程序自己看咯,建议对照着上面的文字看,更容易看得懂。
程序:
#include<stdio.h>#include<stdlib.h>
#include<string.h>
#include<algorithm>
#define maxn 55
#define INF 0x3f3f3f3f
using namespace std;
int f[maxn][maxn][2],n;
char st[maxn];
bool bo(int left,int right)
{
if ((right-left+1)&1)
return false;
int m=(left+right)>>1;
for (int i=left;i<=m;i++)
{
int j=m+i-left+1;
if(st[i]!=st[j])
return false;
}
return true;
}
int dp(int left,int right,bool ok)
{
if (f[left][right][ok]<INF)
return f[left][right][ok];
int len=right-left+1;
if (len==1)
{
if (ok)
return f[left][right][ok]=INF;
else
return f[left][right][ok]=1;
}
int m=(left+right)>>1;
if (ok)
{
for (int i=left;i<right;i++)
{
f[left][right][ok]=min(f[left][right][ok],dp(left,i,1)+1+dp(i+1,right,1));
f[left][right][ok]=min(f[left][right][ok],dp(left,i,0)+1+dp(i+1,right,1));
f[left][right][ok]=min(f[left][right][ok],dp(left,i,1)+1+dp(i+1,right,0));
f[left][right][ok]=min(f[left][right][ok],dp(left,i,0)+1+dp(i+1,right,0));
}
return f[left][right][ok];
}
if (bo(left,right))
f[left][right][ok]=dp(left,m,0)+1;
for (int i=left;i<right;i++)
f[left][right][ok]=min(f[left][right][ok],dp(left,i,0)+right-i);
return f[left][right][ok];
}
int main()
{
memset(f,INF,sizeof(f));
scanf("%st",st+1);
n=strlen(st+1);
printf("%d\n",min(dp(1,n,0),dp(1,n,1)));
return 0;
}
阅读全文
1 0
- SCOI 2007 压缩 C++
- [BZOJ 1068][SCOI 2007]压缩(DP)
- 【BZOJ 1068】【SCOI 2007】压缩 【区间DP】
- BZOJ 1067[SCOI 2007]
- BZOJ 1070 [SCOI 2007]修车
- [BZOJ 1087][SCOI 2005] 互不侵犯King 状态压缩DP
- BZOJ SCOI 2007 修车 费用流
- BZOJ 1066 SCOI 2007 蜥蜴 最大流
- [BZOJ 1072][SCOI 2007]排列perm
- BZOJ 1069 SCOI 2007 最大土地面积 凸包+旋转卡壳
- BZOJ 1070 [scoi 2007] 修车 (zkw费用流)
- [BZOJ 1069][SCOI 2007]最大土地面积(凸包+旋转卡壳)
- [BZOJ 1072] SCOI 2007 排列perm · 动态规划
- BZOJ 1072 [SCOI 2007] 排列perm (状压DP)
- 【BZOJ 1072】【SCOI 2007】排列perm【状压DP】&【STL】
- BZOJ 1067 [SCOI 2007] 线段树 解题报告
- BZOJ 1068 [SCOI 2007] 区间DP 解题报告
- BZOJ 1069 [SCOI 2007] 旋转卡壳 解题报告
- FPGA学习笔记:面向验证和仿真的行为描述语句(2)
- #ifdef __cplusplus extern "C" { #endif /* __cplusplus */
- reducer中处理数组数据的赋值
- Mybatis使用maven打包出现的问题
- web中ajax传值乱码的情况
- SCOI 2007 压缩 C++
- Outline of Machine Learning created by Andrew Ng on Coursera
- 安卓手机数据即使丢失了也可以这样找回来,操作攻略走起!
- php不输出错误信息解决办法
- Android Service的生命周期
- 关于websocket的学习两个Demo
- Android用户界面_布局
- VC进制转换(二进制-十进制-十六进制)
- MySQL通配符过滤数据