• P1092 虫食算


    https://www.luogu.org/problem/show?pid=1092

    好一道搜索题!
    一开始我自己写了一个史上最无脑的搜索,结果只得了10分,全部TLE掉。参考了题解,才发现自己的暴力搜方法不太对,我是枚举数的每一位是每一个数。。。就是好无脑,不超时才怪。

    参考了题解(有些题解有太多太多的剪枝,好像处理得太过繁琐,我参考的题解简单易懂),叙述一下法。
    我们可以这样来搜索:我们记录每个字母在三个数从低位到高位的出现顺序,按照这个顺序搜索当前的字母代表哪个数。
    其中又一些小小的剪枝:

    1).当我们三个数这一位上的字母都赋值后,如果a和b这一位上的数之和或者之和加上进位(假设有进位只能 为1)都不等于c上的数时,那么不能符合条件,return

    2).如果搜索出最高位能够进位,那么也不可以

    还有一个优化,给字母赋数值时,从大往小赋值,以为(最)高位的数不能太大。(最高位不能进位)
    这样就可以AC啦

    先贴一波原创的无脑搜索TLE的10分代码

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm> 
    #include<cmath>
    #include<map>
    using namespace std;
    int n;
    int a[30],b[30],c[30];
    int aa[30],bb[30],cc[30],dd[30];
    bool f[30];
    int p[30];
    bool judge()
    {
        for(int i=0;i<n;i++)
        {
            aa[i]=p[a[n-1-i]];
            bb[i]=p[b[n-1-i]];
            cc[i]=p[c[n-1-i]];
        }
        for(int i=0;i<n;i++) dd[i]=aa[i]+bb[i];
        for(int i=0;i<n;i++) dd[i+1]+=dd[i]/n,dd[i]%=n;
        for(int i=0;i<n;i++) if(dd[i]!=cc[i]) return 0;
        return 1;
    }
    bool check()
    {
        int w=0;
        for(int i=0;i<n;i++)
        {
            if(!p[i]) w++;
            if(w>1) return 0;
        }    
        return 1;
    }
    void dfs()
    {
        if(check()) 
        {
            if(judge())
            {
                 for(int i=0;i<n;i++)
                printf("%d ",p[i]);
                exit(0);
            }
            else return; 
        }
    
        for(int x=n-1;x>=0;x--)
        {
            if(!f[x])
            {
                for(int i=n-1;i>=0;i--){
                if(!p[a[i]])
                {
                    p[a[i]]=x,f[x]=1;
                    dfs();
                    p[a[i]]=0,f[x]=0;
                }
                if(!p[b[i]])
                {
                    p[b[i]]=x,f[x]=1;
                    dfs();
                    p[b[i]]=0,f[x]=0;
                }
                if(!p[c[i]])
                {
                    p[c[i]]=x,f[x]=1;
                    dfs();
                    p[c[i]]=0,f[x]=0;
                }
            }
          }
    
        } 
    }
    int main()
    {
        scanf("%d",&n);
        char C;
        for(int i=0;i<n;i++) {cin>>C;a[i]=C-'A';}
        for(int i=0;i<n;i++) {cin>>C;b[i]=C-'A';}
        for(int i=0;i<n;i++) {cin>>C;c[i]=C-'A';} 
    
        dfs();
        return 0;
    }

    下面是AC代码

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm> 
    #include<cmath>
    #include<map>
    using namespace std;
    int n,cnt;
    int a[30],b[30],c[30];
    int aa[30],bb[30],cc[30];
    bool f[30];//表示i这个数是否被用过 
    int num[30];//num[i]表示i这个字母表示的数 
    int nxt[30];
    void show()//输出 
    {
        for(int i=0;i<n;i++)
         printf("%d ",num[i]);
        exit(0);
    }
    bool judge()
    {
        int last=0;//进位 
        for(int i=n-1;i>=0;i--)
        {
            if((num[a[i]]+num[b[i]]+last)%n!=num[c[i]]) return 0;
            last=(num[a[i]]+num[b[i]]+last)/n;
        }
        return 1;
    }
    bool check()
    {
        for (int i=n-1;i>=0;i--)
         if((num[a[i]]!=-1)&&(num[b[i]]!=-1)&&(num[c[i]]!=-1))
            if((((num[a[i]]+num[b[i]])%n)!=num[c[i]])&&(((num[a[i]]+num[b[i]]+1)%n)!=num[c[i]])) 
               return 0;
        return 1;
    }
    void dfs(int x)//搜索第x个字母是哪个数 
    {
        if(num[a[0]]+num[b[0]]>=n) return;
    
        if(!check()) return;
    
        if(x==n) {if(judge()) show();}
        for(int i=n-1;i>=0;i--)
        if(!f[i])
        {
            num[nxt[x]]=i;
            f[i]=1;
            dfs(x+1);
            f[i]=0;
            num[nxt[x]]=-1; 
        } 
    }
    int main()
    {
        scanf("%d",&n);
        char C;
        for(int i=0;i<n;i++) {cin>>C;a[i]=C-'A';}
        for(int i=0;i<n;i++) {cin>>C;b[i]=C-'A';}
        for(int i=0;i<n;i++) {cin>>C;c[i]=C-'A';} 
        for(int i=n-1;i>=0;i--)
        {
            if(!f[a[i]]) nxt[cnt++]=a[i],f[a[i]]=1;
            if(!f[b[i]]) nxt[cnt++]=b[i],f[b[i]]=1;
            if(!f[c[i]]) nxt[cnt++]=c[i],f[c[i]]=1;
            if(cnt==n) break;//记录搜索的字母顺序 
        }
        //for(int i=0;i<n;i++) printf("%d ",nxt[i]);
        memset(f,0,sizeof(f));
        memset(num,-1,sizeof(num));//因为真正的数值有0,所以一开始初始化为-1 
        dfs(0); 
        return 0;
    }
  • 相关阅读:
    异常处理
    PAT——1048. 数字加密
    PAT——1047. 编程团体赛
    PAT——1046. 划拳
    PAT——1045. 快速排序(25)
    PAT——1044. 火星数字
    PAT——1043. 输出PATest
    PAT——1042. 字符统计
    PAT——1041. 考试座位号
    PAT——1040. 有几个PAT
  • 原文地址:https://www.cnblogs.com/dfsac/p/7587860.html
Copyright © 2020-2023  润新知