zoukankan      html  css  js  c++  java
  • 洛谷P1092虫食算

    题意:

    略略略

    ABCED
    BDACE
    EBBAA

    上面式子的意思是:

    第一行和第二行是加数,第三行是结果。

    并且这是n进制加法,每个字母代表0--n-1中一个。

    字母和数字一一对应。

    这个的结果是1 0 3 4 2

    10324

    04132

    20011

    (允许有前导0)

    10进制加法是满十进一,N进制加法是满n进1.

    (4+2)%5=1;(2+3+1)%5=1;......

    题解:

    一、数组:

    ans[]记录答案,ans[0]代表A对应的数字,开始赋值为-1.

    不能赋值为0,因为0可以为对应的数字。

    use[]标记数字是否被占用。use[0]=true,表示数字0已经赋值给别的字母了。

    二、剪枝:

    先来几个普通的剪枝,(如果想看更多剪枝就看其他题解吧...)

    1)首先是n位,所以最高位不能进1,否则结果是n+1位。

    2)知二推一。

    情况一:知道两个加数和结果(假设为a,b,c),我们可以算出结果为(a+b)%n。

    但我们不知道之前是否有进位。那么如果c既不等于(a+b)%n,也不等于(a+b+1)%n,

    那么c一定是不对的了。

    情况二:知道c和a,b中的一个,假设知道b,那么a=c-b。若a<0,a+=n;

    如果现在推出的a这个数已经被其他字母占用了,并且a-1(有进位)不存在,即<0,

    或者存在但也被其他字母占用了,那么就没有数字对应这个字母,需要return。

    三、搜索顺序(各个顺序的代码和所用时间后面会给出)

    1)按顺序,从A开始搜每个字母代表的数字。

    2)按照我们手推的顺序,从左到右,从上到下,以列一列的搜。

    3)跟第二种差不多..或者一楼的next数组就是这个意思?【笑

    在做靶形数独这个题时,有一种搜的方法是把没填的格子位置记录下来,

    在搜时从当前没填的格子直接跳到下一个没填的格子,不用遍历整张图。

    我们按手推的顺序(上到下,左到右)把遇到的一个个字母装入一个数组中。

    不是从A、B、C....搜,而是从我们手推遇到字母的顺序搜。

    如样例:搜索顺序就是DEACB...

    时间和第二种顺序差不多

    4)倒着搜...玄学

    四、代码

    【代码一】70  3740ms  从A搜

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    int n;
    
    char s1[30],s2[30],s3[30];
    
    int A[30],B[30],C[30];
    
    bool use[30];
    
    int ans[30];
    
    void print()
    {
        for(int i=0;i<n;i++) printf("%d ",ans[i]);
        exit(0);
    }
    
    bool ok()
    {
        int x=0;
        for(int i=n;i>=1;i--)
        {
            int a=ans[A[i]],b=ans[B[i]],c=ans[C[i]];
            if((a+b+x)%n!=c)return false;
            x=(a+b+x)/n;
        }
        return true;
    }
    
    bool check()
    {
        for(int i=n;i>=1;i--)
        {
            int a=ans[A[i]],b=ans[B[i]],c=ans[C[i]];
            if(i==1&&a+b>n)return false;
            if(a!=-1&&b!=-1&&c!=-1)
            {
                if((a+b)%n!=c&&(a+b+1)%n!=c) return false;
            }
            if(a==-1&&b!=-1&&c!=-1)
            {
                int d=c-b;
                if(d<0)d+=n;
                if(use[d]&&use[d-1])return false;
            }
            if(a!=-1&&b==-1&&c!=-1)
            {
                int d=c-a;
                if(d<0)d+=n;
                if(use[d]&&use[d-1])return false;
            }
        }
        return true;
    }
    
    void dfs(int now)
    {
        if(now==n)
        {
            if(ok())print();
            return;
        }
        if(check()==false)return;
        for(int i=0;i<n;i++)
        {
            if(!use[i])
            {
                use[i]=true;
                ans[now]=i;
                dfs(now+1);
                use[i]=false;
                ans[now]=-1;
            }
        }
    }
    
    int main()
    {
        scanf("%d",&n);
        scanf("%s%s%s",s1+1,s2+1,s3+1);
        for(int i=1;i<=n;i++)
        {
            A[i]=s1[i]-'A';
            B[i]=s2[i]-'A';
            C[i]=s3[i]-'A';
        }    
        for(int i=0;i<n;i++)ans[i]=-1;
        dfs(0);
        return 0;
    }

    【代码二】按手推顺序搜  94ms

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    int n;
    
    int pos[4][40];
    
    int ans[30];
    
    char s1[30],s2[30],s3[30];
    
    bool use[30];
    
    void print()
    {
        for(int i=0;i<n;i++) printf("%d ",ans[i]);
        exit(0);
    }
    
    bool ok()
    {
        int x=0;
        for(int i=n;i>=1;i--)
        {
            int a=ans[pos[1][i]],b=ans[pos[2][i]],c=ans[pos[3][i]];
            int xx=a+b+x;
            if(xx%n!=c) return false;
            x=xx/n;
        }
        return true;
    }
    
    bool check()
    {
        if(ans[pos[1][1]]+ans[pos[2][1]]>=n) return false;
        for(int i=1;i<=n;i++)
        {
            int a=ans[pos[1][i]],b=ans[pos[2][i]],c=ans[pos[3][i]];
            if(a!=-1&&b!=-1&&c!=-1)
            {
                if((a+b)%n!=c&&(a+b+1)%n!=c) return false;
            }
            if(a!=-1&&b==-1&&c!=-1)
            {
                int d=c-a;
                if(d<0) d+=n;
                if(use[d]&&(d-1<0||use[d-1])) return false; 
            }
            if(a==-1&&b!=-1&&c!=-1)
            {
                int d=c-b;
                if(d<0)d+=n;
                if(use[d]&&(d-1<0||use[d-1])) return false;
            }
        }
        return true;
    }
    
    void dfs(int x,int y,int has)
    {
        if(has==n)
        {
            if(ok()) print();
            return;
        }
        if(check()==false) return;
        if(y==0) return ;
        if(ans[pos[x][y]]!=-1)
        {
            if(x==3) dfs(1,y-1,has);
            else dfs(x+1,y,has);
        }else
        {
            for(int i=n-1;i>=0;i--)
            {
                if(!use[i])
                {
                    use[i]=true;
                    ans[pos[x][y]]=i;
                    if(x==3)dfs(1,y-1,has+1);
                    else dfs(x+1,y,has+1);
                    use[i]=false;
                    ans[pos[x][y]]=-1;
                }
            }
        }
    }
    
    int main()
    {
        scanf("%d",&n);
        scanf("%s%s%s",s1+1,s2+1,s3+1);
        for(int i=1;i<=n;i++)
        {
            pos[1][i]=s1[i]-'A';
            pos[2][i]=s2[i]-'A';
            pos[3][i]=s3[i]-'A';
        }
        for(int i=0;i<n;i++)ans[i]=-1;
        dfs(1,n,0);
        return 0;
    }

    代码三】 91ms 这样搜仿佛没什么卵用 :-)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    int n,cnt;
    
    int pos[4][30],k[30],ans[30];
    
    char s1[30],s2[30],s3[30];
    
    bool use[30];
    
    void print()
    {
        for(int i=0;i<n;i++) printf("%d ",ans[i]);
        exit(0);
    }
    
    bool ok()
    {
        int x=0;
        for(int i=n;i>=1;i--)
        {
            int a=ans[pos[1][i]],b=ans[pos[2][i]],c=ans[pos[3][i]];
            int xx=a+b+x;
            if(xx%n!=c) return false;
            x=xx/n;
        }
        return true;
    }
    
    bool check()
    {
        if(ans[pos[1][1]]+ans[pos[2][1]]>=n) return false;
        for(int i=1;i<=n;i++)
        {
            int a=ans[pos[1][i]],b=ans[pos[2][i]],c=ans[pos[3][i]];
            if(a!=-1&&b!=-1&&c!=-1)
            {
                if((a+b)%n!=c&&(a+b+1)%n!=c) return false;
            }
            if(a!=-1&&b==-1&&c!=-1)
            {
                int d=c-a;
                if(d<0) d+=n;
                if(use[d]&&(d-1<0||use[d-1])) return false; 
            }
            if(a==-1&&b!=-1&&c!=-1)
            {
                int d=c-b;
                if(d<0)d+=n;
                if(use[d]&&(d-1<0||use[d-1])) return false;
            }
        }
        return true;
    }
    
    void dfs(int now)
    {
        if(now==n+1)
        {
            if(ok()) print();
            return ;
        }
        if(check()==false) return;
        for(int i=n-1;i>=0;i--)
        {
            if(use[i]) continue;
            int anow=k[now];
            use[i]=true;
            ans[anow]=i;
            dfs(now+1);
            use[i]=false;
            ans[anow]=-1;
        }
    }
    
    int main()
    {
        scanf("%d",&n);
        scanf("%s%s%s",s1+1,s2+1,s3+1);
        for(int i=n;i>=1;i--)
        {
            pos[1][i]=s1[i]-'A'; if(!use[pos[1][i]])k[++cnt]=pos[1][i],use[pos[1][i]]=true;
            pos[2][i]=s2[i]-'A'; if(!use[pos[2][i]])k[++cnt]=pos[2][i],use[pos[2][i]]=true;
            pos[3][i]=s3[i]-'A'; if(!use[pos[3][i]])k[++cnt]=pos[3][i],use[pos[3][i]]=true;
        }
        memset(use,0,sizeof(use));
        memset(ans,-1,sizeof(ans));
        dfs(1);
        return 0;
    } 
  • 相关阅读:
    vue表单:输入身份证号码则自动获取对应的年龄和性别,,若不输入身份证号则自己填写年龄和性别
    el-input 电话号码输入时加上空格(344)
    vue图片上传---融合裁剪功能
    shell 基本编程
    virtualbox 安装centos ,运行shell 脚本
    js 检测变量类型
    js deepCopy
    python 安装requests库
    python 识别文件 文件夹
    python 删除非空文件夹
  • 原文地址:https://www.cnblogs.com/zzyh/p/9531891.html
Copyright © 2011-2022 走看看