1 /*状态转移f[i]=min(f[i],f[j]+f[i^j]); 2 就是j状态+i^j状态=i状态,f[i]记录的是从i删除1要的最小步数*/ 3 #include<string.h> 4 #include<stdio.h> 5 #include<algorithm> 6 using namespace std; 7 const int N=100010; 8 int f[N]; 9 int n; 10 char s[20]; 11 int min(int a,int b) 12 { 13 if(a<b) return a; 14 return b; 15 } 16 int can(int x)//x代表的是从原来串中取得的子串,比如abcdef,如果x=111000,那么就是取abc,1代表取,0代表不取 17 { 18 int i,j; 19 int l=0,r=n-1; 20 while (l<=r) 21 { 22 /*两个while是将开头和结尾的每一对1取出来比较*/ 23 while (l<n&&(x&(1<<l))==0) l++;//当遇到1或l>n时跳出 24 while (r>=0&&(x&(1<<r))==0) r--; 25 if (s[l]!=s[r]) return 0;//如果取出来的子串不满足回文就返回0 26 else 27 { 28 l++;r--;//继续取对1 29 } 30 } 31 return 1; 32 } 33 int main() 34 { 35 int i,j; 36 int ca; 37 scanf("%d",&ca); 38 while (ca--) 39 { 40 scanf("%s",s); 41 n=strlen(s); 42 f[0]=0;//一个都不取 43 for (i=1;i<(1<<n);i++)//遍历所有状态,其实可以开个数组,记录一下满足的状态,那样可以省时间吗 44 { 45 if (can(i)) f[i]=1;//满足回文就可以一步删除 46 else f[i]=100;//不满足就置为一个大于n的数 47 } 48 for (i=1;i<(1<<n);i++)//遍历所有状态 49 for (j=(i-1)&i;j;j=(j-1)&i)//删除操作,j是i的下一个状态 50 f[i]=min(f[i],f[j]+f[i^j]);//i^j是在i中删除j剩下的状态,不如1001^1000=0001,0001就是删除1000剩下的 51 printf("%d ",f[(1<<n)-1]);//结果就是删除n个1需要的最小步数,n个1代表n个都要取到 52 } 53 return 0; 54 } 55
11:42:14