• 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.
  • 相关阅读:
    C#开发微信门户及应用(7)-微信多客服功能及开发集成
    C#开发微信门户及应用(6)--微信门户菜单的管理操作
    使用Json.NET来序列化所需的数据
    Winform开发框架里面使用事务操作的原理及介绍
    C#开发微信门户及应用(5)--用户分组信息管理
    C#开发微信门户及应用(4)--关注用户列表及详细信息管理
    基于MVC4+EasyUI的Web开发框架经验总结(3)- 使用Json实体类构建菜单数据
    基于MVC4+EasyUI的Web开发框架经验总结(2)- 使用EasyUI的树控件构建Web界面
    基于MVC4+EasyUI的Web开发框架经验总结(1)-利用jQuery Tags Input 插件显示选择记录
    如何在应用系统中实现数据权限的控制功能
  • 原文地址:https://www.cnblogs.com/20070618hyz/p/12829961.html
Copyright © 2020-2023  润新知