2013 多校第三场 hdu 4628 Pieces

hdu 4628

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4628

思路:状压一下,然后写个check函数判断是否回文就好。

这道题目我真心无语。。 下午先开始我们想贪心,然后我直接敲,WA了,后来找到一个数据,推翻了贪心的想法,然后,马上开始了状态压缩DP,第一遍写了个记忆化,TLE,马上剪枝优化,一交,还是TLE,又把贪心的那个答案拿来剪枝,就这样减一点,交一次,一直TLE。。。 没办法,改掉,又写了个循环递推的,交了几次,一直TLE,和一个队友一直优化,各种方法,反正就是TLE。。 后来队友一看不行,直接上来在我的代码的基础上,把状态转移改写了个背包,竟然就这样过了。。 = =

吃完饭,我马上去网上看别人怎么写的,一看,顿时感觉自己TLE真的是理所当然,学艺不精啊。。

这是我本来写的代码:

for(int i = S-1;i>=0;i--)
{
	d[i] = INF;
    for(int j = i+1;j<=S;j++)
    {
		if((i|j)==j)
		{
			if(is[j-i])
			{
				d[i] = min(d[i],d[j]+1);
			}
		}
	}
}


这是我看了网上的代码后,改写的代码:

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);
		}
	}
}


关键在于里面那个j的循环,也就是枚举可行状态的时候,j = (j+1)|i,这样可以省掉很多的状态,缩短很多的时间,哎,mark一下,又学习了。。。 = =

以下是完整代码:

#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;
       for(int i = 0;i<=S;i++)
       {
           is[i]=0;
           if(check(i)) is[i]=1;
       }
       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;
}


你可能感兴趣的:(2013 多校第三场 hdu 4628 Pieces)