HDU4628

 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

原文地址:https://www.cnblogs.com/okboy/p/3227423.html