hdu 4628 Pieces (状态压缩+二进制枚举+dp)
2013-07-31 09:51
567 查看
Sample Input
Sample Output
2 aa abb
Sample Output
1 2 题意 : 给一个字符串,每次可以删除一个回文串 ,比如 axbdyhba ;可以删 abyba ,剩下 xdh ; 问最少要删多少次能把字符串删除完 ;分析; 首先状态压缩, 因为长度只有16 ;所以顶多是2^16-1 ;每个位1表示存在字母,0表示删除了这个字母 : 则一个所有0和1组成的二进制就可以表示出所有字符串的状态 : 比如 abcde : 他的状态是 11111 , ab_d_ 的状态是11010 ,表示删除第四个和第五个 :所以2^5-1能表示出所有你的子集,也就是字符串的所有状态 .而一个二进制对应着一个整数,利用哈希表,可以记录状态 is[i]=1 ,表示这个状态是回文串,is[i]=0;表示这个状态不是回文串 ; 比如 串 acda , a_da 是一个回文串,二进制位1011 ,对应的整数位11 ;所有 is[11]=1 ;当枚举出了所有的状态后,就可以dp过了 ; d[i] 表示 最少需要多少步能到达 i状态 ; 所以最终答案是, 最少需要多少步能到达全部删除完的状态,也就是 ,000000 , 即 d[0] ; 而 d[i]是通过后面得 d[j]状态通过删除字母到达d[i]状态的, 所以j>i 并且 j表示的二进制数的1的个数一定要比i多 ,因为1的个数就代表字母的个数, j状态要通过删除一些字母才能到达i状态,所以j的二进制里的1个数要比i多;也就是 要保证 (j|i)==j ,才能使用状态转移方程 d[i]=min(d[i],d[j]+1) ; 这是dp部分的代码 ;但是会T ; for(inti = S-1;i>=0;i--) { d[i] = INF; for(int j = i+1;j<=S;j++) //j要比i大 { if((i|j)==j) //并且j里面的1个数要比i多 { if(is[j-i]) //多出的1就是要删除的串(j-i) ,还要判断删除的串是否是回文串; { d[i] =min(d[i],d[j]+1); } } }} 这是优化过后的 :for(int i = S-1;i>=0;i--) { d[i]= INF; for(intj = i+1;j<=S;j = (j+1)|i) // j = (j+1)|i能省去很多状态. { //因为每次都更新j ;j的1个数都是比i多的 ; if(is[j-i]) { d[i]= min(d[i],d[j]+1); } } } AC的代码 : #include <stdio.h> #include <string.h> #include <math.h> #include<algorithm> using namespace std; const int INF = 1000000000 ; char str[22]; int n; char tmp[22]; int check(int s) { //printf("s = %d\n",s); int c=0; for(int i=0;i<n;i++) { if((s&(1<<i))!=0) { tmp[c++] = str[i]; } } tmp[c] = '\0'; //puts(tmp); for(int i=0,j=c-1;i<j;) { if(tmp[i]!=tmp[j]) { return 0; } else { i++; j--; } } return 1; } int d[1<<17]; int is[1<<17]; int main() { int T; scanf("%d",&T); while(T--) { scanf("%s",str); n = strlen(str); int S = (1<<(n))-1; //共有2^n-1 种状态 for(int i = 0;i<=S;i++) //二进制没举所以状态 { is[i]=0; if(check(i)) is[i]=1; //如果i状态是回文串,标记; } d[S] = 0; //刚开始 ,一步没动; for(int i = S-1;i>=0;i--) { d[i] = INF; for(int j = i+1;j<=S;j = (j+1)|i) { if(is[j-i]) { d[i] = min(d[i],d[j]+1); } } } printf("%d\n",d[0]); } return 0; }
相关文章推荐
- HDU 4628 Pieces(状态压缩DP)
- hdu 4628 Pieces (状态压缩dp)
- HDOJ 4628 - Pieces 状态压缩DP..枚举所有子集进行更新
- hdu 4628 Pieces 状态压缩DP
- hdu 4628 Pieces(状态压缩DP)
- HDU 4628 Pieces(DP + 状态压缩)
- hdu - 4628 - Pieces(状态压缩dp)
- hdu 4628 Pieces(状态压缩+DP,4级)
- HDU 4628 Pieces(状态压缩dp)
- hdu 4628 Pieces 状态压缩DP
- hdu 4628 Pieces (状态压缩dp)
- hdu 1074 DP 二进制状态压缩
- hdu 4628 Pieces(状态压缩+记忆化搜索)
- hdu 4628 状态压缩dp
- hdu 4628 Pieces(状态压缩+记忆化搜索)
- HDU4628+状态压缩DP
- HDU4628+状态压缩DP
- hdu 4628 - Pieces(压缩dp)
- HDU-1047(DP-二进制状态压缩)
- HDU-1047(DP-二进制状态压缩)