• 虫食算(暴力搜索)


    P1092 虫食算


    题目正解是(O(2^NN^3))的高斯消元加上二进制枚举

    然而这并不妨碍我们搜索的脚步。(滑稽

    我们可以考虑按照位置从左往右进行搜索,每列最多搜索两个数,在利用之间的关系计算出来剩下的一个数。可以根据这个剪枝

    然后就可以考虑写代码了

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    const int N=28;
    int M[N][3],n;
    int D[N],V[N];//D为进位,V为第i个字母的数值
    bool G[N],Num[N];//G为第i个字母是否被填充过,Num为某个数字是否被使用过
    int read_char()
    {
        char c=getchar();
        while(c>'Z'||c<'A') c=getchar();
        return c-'A'+1;
    }
    bool fill(int pos,int val)
    {
        if(!G[pos]&&!Num[val])
        {
            G[pos]=true;
            V[pos]=val;
            Num[val]=true;
            return true;
        }
        if(V[pos]==val) return true;
        return false;
    }
    inline int calc(int now)
    {
        return V[M[now][1]]+V[M[now][2]]+D[now];
    }
    inline void reset(int pos)
    {
        G[pos]=false;
        Num[V[pos]]=false;
        V[pos]=-1;
    }
    void Exit()
    {
        /*for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
                printf("%d",V[j]);
            printf("
    ");
        }*/
        for(int i=1;i<=n;i++)
            printf("%d ",V[i]);
        exit(0);
    }
    void dfs(int now)
    {
        if(now==n+1)//终止条件
        {
            if(!D[now])//D数组的意思是,now列有没有进位
                Exit();
            return ;
        }
        bool N1=G[M[now][1]],N2=G[M[now][2]],N3=G[M[now][3]];//Ni表示从上往下数第i个数有没有被使用
        if(!(N1&&N3&&!N2))//如果不是第一个数和第三个数有值,第二个数没有数值的情况
        {
            for(int i=n-1;i>=0;i--)
            {
                if(!N1&&!fill(M[now][1],i))  continue;//如果第一个数没有数值,则尝试填入。能否成功由fill函数返回,如果能填进去i或者是第一个数的值是i,返回true
                //如果N1为true,不进行上面的操作
                for(int j=n-1;j>=0;j--)
                {
                    if(!N2&&!fill(M[now][2],j))  continue;//同理
                    int C=calc(now);//计算出第三个数
                    if(fill(M[now][3],C%n))//判断填入是否合法
                    {
                        D[now+1]=C/n;//计算进位
                        dfs(now+1);//下一层递归
                        D[now+1]=0;//进位重置
                        if(!N3) reset(M[now][3]);//复位
                    }
                    if(N2)  break;//如果N2为true,则这个循环只执行一次
                    reset(M[now][2]);//重置
                }
                if(N1)  break;
                reset(M[now][1]);//同上
            }
        }
        else
        {
            int B=(V[M[now][3]]+n-V[M[now][1]]-D[now])%n;//计算出中间的数值来
            if(fill(M[now][2],B))
            {
                D[now+1]=(V[M[now][1]]+D[now]+B)/n;
                dfs(now+1);
                D[now+1]=0;
                reset(M[now][2]);
            }
        }//其实还可以更快,即是根据后两个数值,计算出第一个数来
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=3;i++)
            for(int j=n;j>=1;j--)
            M[j][i]=read_char();//读入数据
        for(int i=1;i<=n;i++)   reset(i);
        dfs(1);
    }
    
  • 相关阅读:
    PostgreSQL的德哥教程
    pgbench的使用简介
    pg生成日期序列
    在Intellij IDEA 12中Tomcat无法调试
    如何使用命令行来控制IIS服务的启动和停止
    SharePoint Support Engineer 常用技术点
    测试博文写作
    C#数字进制间与字符串类型相互转换
    [转载]INNO Setup 使用笔记
    unity3d 游戏开发引擎
  • 原文地址:https://www.cnblogs.com/Lance1ot/p/9781560.html
Copyright © 2020-2023  润新知