题目描述
著名科学家卢斯为了检查学生对进位制的理解,他给出了如下的一张加法表,表中的字母代表数字。 例如:
+ L K V E
L L K V E
K K V E KL
V V E KL KK
E E KL KK KV
其含义为:
\(L+L=L\),\(L+K=K\),\(L+V=V\),\(L+E=E\)
\(K+L=K\),\(K+K=V\),\(K+V=E\),\(K+E=KL\)
……
\(E+E=KV\)
根据这些规则可推导出:\(L=0\),\(K=1\),\(V=2\),\(E=3\)
同时可以确定该表表示的是4进制加法
输入格式
\(n(n≤9)\)表示行数。
以下\(n\)行,每行包括\(n\)个字符串,每个字串间用空格隔开。(字串仅有一个为‘+’号,其它都由大写字母组成)
输出格式
1.各个字母表示什么数,格式如:\(L=0\),\(K=1\),……按给出的字母顺序。
2.加法运算是几进制的。
3.若不可能组成加法表,则应输出“ERROR!”
输入样例
+ L K V E
L L K V E
K K V E KL
V V E KL KK
E E KL KK KV
输出样例
L=0 K=1 V=2 E=3
4
13ms / 688.00KB ,其实可以说还算快的吧。
题目再次复述
1.字母都不同
2.在限定进制内加减法
3.第一行第一列字母排列相等
有些人这么想,枚举每一个字母,不过--
正常人应该可以明白`进制为n`吧
仔细分析一下,可以发现每个字母$ch$在$0 \leq ch \leq n-1$
那不就是迎刃而解接了吗?
1. 每个字母依次赋与$0$到$(n-1)$
2. 依次判断是否符合
note:本人码风可能有点丑
```cpp
#include<bits/stdc++.h>
#define INF 1e9
using namespace std;
const int N=12,M=100;
char s[N][N][M];// s[i][j][k]为第i行第j列的第k个字母
int num[M];
int n;
int main(){
scanf("%d",&n);
for(int i=1;i<=26;i++) num[i]=INF;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%s",s[i][j]+1);
for(int i=2;i<=n;i++) num[s[1][i][1]-'A'+1]=i-2; //每个字母一侧赋值
for(int i=2;i<=n;i++)
for(int j=2;j<=n;j++){//两两配对
int combine1=num[s[1][j][1]-'A'+1];
int combine2=num[s[i][1][1]-'A'+1];
int len=strlen(s[i][j]+1);
int p1=0,t=1;
for(int k=1;k<=len;k++){
p1+=num[s[i][j][len-k+1]-'A'+1]*t;
t*=(n-1);
}//两数之和转为n进制
int p2=combine1+combine2//字母权相加
if(p1!=p2){
puts("ERROR!");
return 0;
}
}
for(int i=2;i<=n;i++){
printf("%c=%d",s[1][i][1],num[s[1][i][1]-'A'+1]);//输出
if(i!=n) printf(" ");
}
printf("\n%d\n",n-1);
return 0;
}
还没有结束。。。
是什么原因呢?
呵呵。
谁说的必须依次赋值?
每个字母依次赋与\(0\)到\((n-1)\)
但不能重复哦!
#include<bits/stdc++.h>
#define INF 1e9
using namespace std;
const int N=12,M=100;
int n;
char s[N][N][M];
int num[M];//第i个字母的赋值
bool used[M]; //i数是否用过
int sol(int t){
if(t>n){
bool f=false;
for(int i=2;i<=n;i++){
for(int j=2;j<=n;j++){
int combine1=num[s[1][j][1]-'A'+1];
int combine2=num[s[i][1][1]-'A'+1];
int len=strlen(s[i][j]+1);
int p1=0,t=1;
for(int k=1;k<=len;k++){
p1+=num[s[i][j][len-k+1]-'A'+1]*t;
t*=(n-1);
}
int p2=combine1+combine2;
if(p1!=p2){
f=true;
break;
}//上段就是比较
}
if(f) break;
}
if(!f){
for(int i=2;i<=n;i++){
printf("%c=%d",s[1][i][1],num[s[1][i][1]-'A'+1]);
if(i!=n) printf(" ");
}
printf("\n%d\n",n-1);
return -1;
}//上段就是输出
return 0;
}
for(int i=0;i<n-1;i++) if(!used[i]){
used[i]=true;
num[s[1][t][1]-'A'+1]=i;//放进去
int nw=sol(t+1);
if(nw==-1) return -1;//回朔
num[s[1][t][1]-'A'+1]=INF;
used[i]=false;
}
return 0;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=26;i++) num[i]=INF;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%s",s[i][j]+1);
memset(used,0,sizeof(used));
int nw=sol(2);//结束了吗?
if(nw!=-1) puts("ERROR!");
return 0;
}
终于做完了,分析一下时间复杂度
\(O(n!·n^2·Len) (n \leq 9)\)
(我长度算的3)
再加上一些杂七杂八的优化,\(break\),稳稳的就\(AC\)了。