hdu 4403 A very hard Aoshu problem 状态压缩

题意:告诉你一串数字,添加一个=号和若干+号,使得数字变成等式。其中+号不能重复出现,+号位置不同就记为不同的等式。求等式的个数。

题解:我是用状态压缩来解得。。哈哈。。没办法,dfs没学好,别人大都是直接dfs的。若数字长度为n,令m=pow(2,n-1)-1,则0~m就可以表示所有加号的情况了,其中1表示+,0表示空。然后枚举所有加号情况,枚举所有等号位置,计算等式是否成立即可。这个写起来还算可以,不过我浪费了n多时间,把f数组定义成了char类型,无语了。


代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <map>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=1e5+10;
char a[16];
int f[20];
void init()
{
    int i,j,k;
    f[0]=1;
    for(i=1;i<20;i++)
    {
        f[i]=f[i-1]<<1;
        //printf("%d\n",f[i]);
    }
}
int pows(int a,int b)
{
    int s=1;
    for(int i=0;i<b;i++)
        s=s*a;
    return s;
}
int main()
{
    init();
    while(scanf("%s",a)!=EOF)
    {
        if(a[0]=='E')break;
        int i,j,k,n,m;
        n=strlen(a);
        m=pows(2,n-1)-1;
        int p,q,ans=0,c,flag;
        for(i=0;i<n-1;i++)//枚举等号位置
        {
            for(j=0;j<=m;j++)//枚举所有加号情况,1表示该位有+
            {
                c=p=q=flag=0;
                c=c*10+(a[0]-'0');
                for(k=0;k<n-1;k++)//遍历计算等式是否成立
                {
                    if(k==i)
                    {
                        q+=c;
                        c=0;
                        flag=1;
                    }
                    else if(f[n-2-k]&j)
                    {
                        if(!flag)q+=c;
                        else p+=c;
                        c=0;
                    }
                    c=c*10+(a[k+1]-'0');
                }
                p+=c;
                if(p==q)
                {
                    ans++;
                   /* 
                   //输出所有的等式
                   for(int l=0;l<n-1;l++)
                        if(f[n-2-l]&j)printf("1");
                        else printf("0");
                    printf("\n");
                    for(int l=0;l<n;l++)
                    {
                        printf("%c",a[l]);
                        if(l==i)printf("=");
                        else if(l!=n-1&&(f[n-2-l]&j))printf("+");
                    }
                    printf("\n");*/
                }
            }
        }
        printf("%d\n",ans/2);//由于遍历的时候,等号位无论是1还是0都会输出相同的结果,所以需要除以2
    }
    return 0;
}
/*
11111111111111
414

1111111111111
2
*/


你可能感兴趣的:(状态压缩)