题解又双叒叕来了!
告诉大家一个有用的东西:
若不会有错,则进制=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; }