• NOIP提高组1998进制位题解


    题解又双叒叕来了!

    告诉大家一个有用的东西:

    若不会有错,则进制=n,且数值都是连续的

    因为:

    1必须有(不然十位搞鬼)

    然后就:

    1 1 2 2必须有,其它数字以此类推

    主体思路:DFS

    一看到题,有点蒙,大致思考了以后,我想起了以前做过的NOIP2004年的虫食算鬼畜竖式题

    于是,我构起了这道题的大致框架:将矩阵分解成一个个竖式(在程序中有Size个竖式),并对每个字母所对应的数进行枚举,最后写出答案。

    在做程序中,需要思考以下几个问题:

    (一)进制的枚举

    最开始我以为进制是在M(不重复字母个数),和N-1(第一行的字母总数)之间,后来发现两者的值一直相同,这个问题就引刃而解了。想多了

    (二)每个字母所对应的数的枚举

    太简单了!(FJJ说的),这个就是本程序搜索的主体,本蒟蒻认为只要是学过DFS的人都会——定义一个递归函数,函数有一个参量,就是矩阵(输入的那个)的第一行的每一列(从2到N),指的是每个字母,在递归函数中放一个循环,从0循环到Top-1(注意是从0开始,不是1,Top指的是Top进制),枚举每个字母所代表的数——解决了!

    在这里我还用了STL里面的map,用在这里是将一个字符串作为下标来存储布尔值或整形

    (三)如何将矩阵做成竖式

    将整个矩阵扫一遍,用一个数组存现在所在的那一列的第一个字母(加数一),用另一个字母存储所在的那一行的第一个字母(加数二),用第三个数组存储那一行那一列的字母(可能是字符串),这个问题也就解决了。

    (四)如何判断这个枚举是正确的(前方高能,呼叫博主)

    首先,我们要加刚才准备好的竖式按枚举出来的答案一一转换为数字:

    先推荐一种数据结构转换成数字的代码然后就是就是转换了,我的思路是用一个空数组计算得到的两个加数的和(这里用到了高精度的思想),在和原来的和进行对比,一样则通过,不一样则表示枚举有问题(要对每一个竖式进行检验)而这两个函数的入口应该放在深搜函数的开始处,并且需要特判是否枚举完每个字母

    (五)输出

    不想讲了,它叫我们怎么输出就怎么输出

    总结:

    时间复杂度:O(1)(进制枚举)*O(N)(字母枚举)*O(N)(每个字母所对应的数字的枚举)*O(N)(每个扫描竖式)*O(N)(每个竖式的确认)=O(N^4)——不会超时(N<=9)——不需要剪枝了(我其实是懒得剪)。

    有一点要注意:每个竖式转换成数字时数字竖式数组要时时清空,要不然就会出现WA的情况。

    上代码

    #include <bits/stdc++.h>
    using namespace std;
    
    struct Unsigned{
        int V[99];
        int Size;
    };
    
    string Num1[99],Num2[99],Sum[99];
    Unsigned Queue1[99],Queue2[99];
    map<char,bool> Visited;
    map<char,int> Judge2;
    Unsigned Queue3[99];
    string Map[99][99];
    int ACanswer[99];
    Unsigned Judge3;
    bool Used[99];
    int N,Size,M;
    int Top;
    bool Judge(void){
        for(int i=1;i<=Size;i++){
            memset(&Judge3,0,sizeof(Judge3));
            Judge3.Size=max(Queue1[i].Size,Queue2[i].Size);
            for(int j=0;j<Judge3.Size;j++){
                Judge3.V[j]=Judge3.V[j]+Queue1[i].V[j]+Queue2[i].V[j];
                Judge3.V[j+1]=Judge3.V[j]/Top;
                Judge3.V[j]=Judge3.V[j]%Top;
            }
            if(Judge3.V[Judge3.Size]>0)
                Judge3.Size++;
            if(Judge3.Size!=Queue3[i].Size)
                return false;
            for(int j=0;j<Judge3.Size;j++)
                if(Judge3.V[j]!=Queue3[i].V[j])
                    return false;
        }
        return true;
    }
    void Print(void){
        for(int i=2;i<=N;i++){
            int Out=Judge2[Map[1][i][0]];
            cout<<Map[1][i]<<"="<<Out<<" ";
        }
        cout<<endl;
        cout<<Top<<endl;
        exit(0);
    }
    void Made(void){
        memset(&Queue1,0,sizeof(Queue1));
        memset(&Queue2,0,sizeof(Queue2));
        memset(&Queue3,0,sizeof(Queue3));
        for(int i=1;i<=Size;i++){
            for(int j=Num1[i].size()-1;j>=0;j--)
                Queue1[i].V[Queue1[i].Size++]=Judge2[Num1[i][j]];
            for(int j=Num2[i].size()-1;j>=0;j--)
                Queue2[i].V[Queue2[i].Size++]=Judge2[Num2[i][j]];
            for(int j=Sum[i].size()-1;j>=0;j--)
                Queue3[i].V[Queue3[i].Size++]=Judge2[Sum[i][j]];
        }
    }
    void Depth_First_Search(int Last){
        if(Last==N+1){Made();
            if(Judge()==true)
                Print();
            return;
        }
        for(int i=0;i<Top;i++){
            if(Used[i]==false){
                if(Judge2[Map[1][Last][0]]==-1){ 
                    Used[i]=true;
                    Judge2[Map[1][Last][0]]=i;
                    Depth_First_Search(Last+1);
                    Judge2[Map[1][Last][0]]=-1;
                    Used[i]=false;
                }
            }
        }
    }
    int main(void){
        cin>>N;
        for(int i=1;i<=N;i++)
            for(int j=1;j<=N;j++)
                cin>>Map[i][j];
        for(int i=2;i<=N;i++){
            for(int j=2;j<=N;j++){
                for(int k=0;k<Map[i][j].size();k++)
                    if(Visited[Map[i][j][k]]==false)
                        Visited[Map[i][j][k]]=true,M++;
                Sum[++Size]=Map[i][j];
                Num1[Size]=Map[i][1];
                Num2[Size]=Map[1][j];
            }
        }
        for(int i=2;i<=N;i++)
            Judge2[Map[i][1][0]]=-1;
        for(Top=N-1;Top<=M;Top++){
            Depth_First_Search(2);
        }
            cout<<"ERROR!"<<endl;
        return 0;
    }    

    你学废了吗?

    学废了扣1,没学废扣眼珠子

    最后,请大家:

    小蒟蒻ΩωΩ I AK IOI.
  • 相关阅读:
    MDK软件2020年到期和谐方法
    TinyMCE插件CodeSample前后端应用
    KEIL MDK编译后的代码量和RAM使用详解
    pdf密码解除工具
    Keil c中自定义带可变参数的printf函数
    关于"云服务器被检测到对外攻击已阻断该服务器对其它服务器端口的访问"的解决措施
    在 __CC_ARM 编译器环境下,使用$Sub$$ 与 $Super$$ 的“补丁”功能
    thinkphp前台html格式化输出日期
    ELINK编程器典型场景之序列号烧写
    数据在数组中存储的顺序:小端 OR 大端模式 详解
  • 原文地址:https://www.cnblogs.com/20070618hyz/p/12829961.html
Copyright © 2020-2023  润新知