题解 P1013 【进制位】

题目描述

著名科学家卢斯为了检查学生对进位制的理解,他给出了如下的一张加法表,表中的字母代表数字。 例如:

+    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

AC记录

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;
}

还没有结束。。。
P1013 进制位

是什么原因呢?

呵呵。

谁说的必须依次赋值?

每个字母依次赋与\(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\)了。

猜你喜欢

转载自www.cnblogs.com/Dark-Lord/p/11851570.html
今日推荐