zoukankan      html  css  js  c++  java
  • 虫食算(暴力搜索)

    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);
    }
    
  • 相关阅读:
    Nodejs 接收RabbitMQ消息
    c#后台线程更新界面
    Nodejs JSON.parse()无法解析ObjectID和ISODate的问题
    【百度小程序】细数百度小程序踩的坑
    工作中可能用到的工具
    input输入文字的时候背景会变色,如何去掉呢?
    百度小程序开发工具不能预览
    引入外部 CDN失效时--怎么加载本地资源文件(本文以jquery为例)
    swiper插件遇到的坑
    原生JS实现JQuery的addClass和removeClass
  • 原文地址:https://www.cnblogs.com/Lance1ot/p/9781560.html
Copyright © 2011-2022 走看看