虫食算(搜索)

题目:

虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母。来看一个简单的例子:

      43#9865#045   
  +   8468#6633   
  =   44445506678

  其中#号代表被虫子啃掉的数字。根据算式,我们很容易判断:第一行的两个数字分别是5和3,第二行的数字是5。
  现在,我们对问题做两个限制:
  首先,我们只考虑加法的虫食算。这里的加法是N进制加法,算式中三个数都有N位,允许有前导的0。
  其次,虫子把所有的数都啃光了,我们只知道哪些数字是相同的,我们将相同的数字用相同的字母表示,不同的数字用不同的字母表示。如果这个算式是N进制的,我们就取英文字母表午的前N个大写字母来表示这个算式中的0到N-1这N个不同的数字:但是这N个字母并不一定顺序地代表0到N-1)。输入数据保证N个字母分别至少出现一次。

       BADC   
      + CRDA   
      = DCCC

  上面的算式是一个4进制的算式。很显然,我们只要让ABCD分别代表0123,便可以让这个式子成立了。你的任务是,对于给定的N进制加法算式,求出N个不同的字母分别代表的数字,使得该加法算式成立。输入数据保证有且仅有一组解。

如:

5ABCED
BDACE
EBBAA

ABCDE都是相同的数,ABCED+BDACE=EBBAA,求它的A,B,C,D,E的数值。

思路:可不可以一步一步枚举,A=1到10,B=1到10......是可以但是(忘给了一个条件n<27)惊恐

。。。。。。无语发火恶心吧

我们也可以dfs一下,一步一步进行除,但是(n<27


。。。。。。发火

我们也可以对dfs进行优化,两步两步除,但是(n<27)


。。。。。。发火

只能三步三步除了。。。。。。

先是读入(建议用二维数组,方便一点)

void read()
{
    scanf("%d",&n);
    for (int i=0; i<3; i++){//总共有三行数。。。
        while (ch<'A' || ch>'Z') ch=getchar();
        for (int j=1; j<=n; j++) a[i][j]=ch-'A',ch=getchar();
    }
}

接下来我来解释一下我的个个变量的意义:

int f[30];//他算出来的数值
int a[3][30];//读入的ABCDE......
int g[30];//判断其是否计算过
int jw[30];//计算储存数值
int n;//读入的个数
bool ok=0;//判断是否输出
char ch;//用在快读中

这样就可以进行递推啦!(dfs(0,n))

if (x<2){//当x=0,或x=1时
        int k=1-x;
        if (!f[a[x][y]]){//判断是否用过
            if (f[a[k][y]] && f[a[2][y]]){//如果俩都用过
                if (!g[(f[a[2][y]]-f[a[k][y]]-jw[y+1]+n)%n]){//判断是否计算过
		    f[a[x][y]]=(f[a[2][y]]-f[a[k][y]]-jw[y+1]+n)%n+1;
                    g[f[a[x][y]]-1]=1;
                    dfs(x+1,y);//递推下一位
                    if (ok) return;//如果已经输出了,跳出dfs
                    g[f[a[x][y]]-1]=0;//回溯一步
                    f[a[x][y]]=0;//同上
                }
                return;//跳出循环
            }
            for (int i=n-1; i>=0; i--) if (!g[i]){//判断
                f[a[x][y]]=i+1;
                g[f[a[x][y]]-1]=1;
                dfs(x+1,y);
                g[f[a[x][y]]-1]=0;
                f[a[x][y]]=0;
            }
            return;
        }
        dfs(x+1,y);//dfs一下
        return;
    }

 if (x==2){//和上面的差不多,稍作修改
        if (!f[a[x][y]]){
            f[a[x][y]]=(f[a[0][y]]-1+f[a[1][y]]-1+jw[y+1])%n+1;
            if (!g[f[a[x][y]]-1]){
                g[f[a[x][y]]-1]=1;
                jw[y]=(jw[y+1]+f[a[0][y]]-1+f[a[1][y]]-1)/n;
                dfs(0,y-1);
                g[f[a[x][y]]-1]=0;
            }
            f[a[x][y]]=0;
            return;
        }
        if ((f[a[0][y]]-1+f[a[1][y]]-1+jw[y+1])%n==f[a[2][y]]-1){//判断
            jw[y]=(jw[y+1]+f[a[0][y]]-1+f[a[1][y]]-1)/n;
            dfs(0,y-1);
        }
        return;
    }

下面是输出

if (y==0){//如果算完了
        if (f[a[0][1]]-1+f[a[1][1]]-1+jw[2]==f[a[2][1]]-1){//如果满足条件
            for (int i=0; i<n-1; i++) printf("%d ",f[i]-1);
            printf("%d",f[n-1]-1);
            ok=1;//让下面一直跳出循环
        }
        return;//return掉
    }

这样基本上就完事了

下面是代码(不是伪的)

#include<bits/stdc++.h>
int f[30];
int a[3][30];
int g[30];
int jw[30];
int n;
int ok;
char ch;
void dfs(int x,int y){
    if (ok) return;
    if (y==0){
        if (f[a[0][1]]-1+f[a[1][1]]-1+jw[2]==f[a[2][1]]-1){
            for (int i=0; i<n-1; i++) printf("%d ",f[i]-1);
            printf("%d",f[n-1]-1);
            ok=1;
        }
        return;
    }
    if (x<2){
        int k=1-x;
        if (!f[a[x][y]]){
            if (f[a[k][y]] && f[a[2][y]]){
                if (!g[(f[a[2][y]]-f[a[k][y]]-jw[y+1]+n)%n]){
					f[a[x][y]]=(f[a[2][y]]-f[a[k][y]]-jw[y+1]+n)%n+1;
                    g[f[a[x][y]]-1]=1;
                    dfs(x+1,y);
                    if (ok) return;
                    g[f[a[x][y]]-1]=0;
                    f[a[x][y]]=0;
                }
                return;
            }
            for (int i=n-1; i>=0; i--) if (!g[i]){
                f[a[x][y]]=i+1;
                g[f[a[x][y]]-1]=1;
                dfs(x+1,y);
                g[f[a[x][y]]-1]=0;
                f[a[x][y]]=0;
            }
            return;
        }
        dfs(x+1,y);
        return;
    }
    if (x==2){
        if (!f[a[x][y]]){
            f[a[x][y]]=(f[a[0][y]]-1+f[a[1][y]]-1+jw[y+1])%n+1;
            if (!g[f[a[x][y]]-1]){
                g[f[a[x][y]]-1]=1;
                jw[y]=(jw[y+1]+f[a[0][y]]-1+f[a[1][y]]-1)/n;
                dfs(0,y-1);
                g[f[a[x][y]]-1]=0;
            }
            f[a[x][y]]=0;
            return;
        }
        if ((f[a[0][y]]-1+f[a[1][y]]-1+jw[y+1])%n==f[a[2][y]]-1){
            jw[y]=(jw[y+1]+f[a[0][y]]-1+f[a[1][y]]-1)/n;
            dfs(0,y-1);
        }
        return;
    }
}
void read()
{
    scanf("%d",&n);
    for (int i=0; i<3; i++){
        while (ch<'A' || ch>'Z') ch=getchar();
        for (int j=1; j<=n; j++) a[i][j]=ch-'A',ch=getchar();
    }
}
int main(){
	read();
    dfs(0,n);
    return 0;
}

我这样的算法并不是最好的但是还可以,还可以四步四步算,五步五步算......但是有一种更好的方法——高斯消元,不会,所以没打。

谢谢!



猜你喜欢

转载自blog.csdn.net/qq_40669010/article/details/80447265