题目传送门


题目描述

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

来看一个简单的例子:

  43#98650#45+8468#6633=44445506978

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

    BADC+CBDA=DCCC

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


输入格式

包含4行。第一行有一个正整数N,后面的3行每行有一个由大写字母组成的字符串,分别代表两个加数以及和。这3个字符串左右两端都没有空格,从高位到低位,并且恰好有N位。


输出格式

包含一行。在这一行中,应当包含唯一的那组解。解是这样表示的:输出N个数字,分别表示A,B,C……所代表的数字,相邻的两个数字用一个空格隔开,不能有多余的空格。


样例

样例输入:

5
ABCED
BDACE
EBBAA

样例输出:

1 0 3 4 2


数据范围与提示

对于全部的数据,保证有N≤26。


题解

官方正解是高斯消元,不得不承认高斯消元用来做这道题的确要比搜索简单。

先来算一下时间复杂度,高斯消元:O(${n}^{3}$),搜索:O(${n}^{n}$)。

不管你怎么说,我感觉${n}^{n}$挺帅的。

所以我就去搜索了哇~

显然不能直接爆搜,卡长卡的好没准能跑过n=9,n≥10想都别想了。

那么考虑剪枝:

为简便,地一个字符串称为A,第二个字符串称为B,第三个字符串称为C。

首先你肯定会想到,如果A+B肯定不能得到C,那么就不要往下搜了。

这里需要注意的是,有可能会存在进位。

然后接着考虑,小学的时候数学老师教给你竖式加法的时候,我们都是从最右边网左算。

那么转换到这道题,我们也可以从右往左搜,这样就能更快的把枝剪掉了(注意你的judge函数要优秀)。

还有一种情况,就是如果最前面出现了进位,那么是要剪掉的,所以我们先搜大的数可以更快的出现进位,进而更快的剪掉这个枝。

所以从大往小搜必不可少。

有了这些我就可以轻松A掉这道题了,但是作为一名卓越的OIER,我们还要考虑怎么让代码跑的更快。

所以我就讲一下所有的剪枝:

1.最前面出现进位直接return false,或者A和B串开头位相加比C串开头位大,也要return false。

2.从左往右开始judge,首先,在A,B,C串都没有出现有字母没有赋值的情况的时候,可以按照严格的带进位的加法进行判断。

3.在出现了一个数没有赋值之后,我们就要按照考虑进位与不进位开始考虑了。

  $\alpha$.最好想到的就是无论进不进位都无法满足的话,就return false。

  $\beta$.如果当前位有两个数已经赋值,一个数还没有赋值,那么如果根据这两个数所算出来的第三个数已经被使用(赋值不能重复),那么可以提前剪掉。

如果这些都能满足的话,则继续往前搜。


代码时刻

#include<bits/stdc++.h>
using namespace std;
bool vis[27];
int wzc[27];
int ans[27];
int n;
int a[27],b[27],c[27];
int sor[27],cnt;
char ch1[27],ch2[27],ch3[27];
inline bool _wzc()//judge
{
int wzc=0,_=0;
if(ans[a[0]]+ans[b[0]]>=n)return 0;//判断开头进不进位
if(ans[c[0]]!=-1)//还是在开头剪枝
{
if(ans[a[0]]>ans[c[0]]||ans[b[0]]>ans[c[0]])return 0;
if(ans[a[0]]!=-1&&ans[b[0]]!=-1&&ans[a[0]]+ans[b[0]]!=ans[c[0]]&&ans[a[0]]+ans[b[0]]+1!=ans[c[0]])return 0;
}
for(int i=n-1;i>=0;i--)//全都被赋过值
{
if(ans[a[i]]==-1||ans[b[i]]==-1||ans[c[i]]==-1)//出现有没有被赋过值的
{
_=i;
break;
}
if((ans[a[i]]+ans[b[i]]+wzc)%n!=ans[c[i]])return 0;//严格带进未搜索
wzc=(ans[a[i]]+ans[b[i]]+wzc)/n;
}
for(int i=_;i>=0;i--)//开始考虑进位与不进位,以下分情况,注意代码中“!=”和“==”。
{
if(ans[a[i]]!=-1&&ans[b[i]]!=-1&&ans[c[i]]!=-1)
if((ans[a[i]]+ans[b[i]])%n!=ans[c[i]]&&(ans[a[i]]+ans[b[i]]+1)%n!=ans[c[i]])return 0;
if(ans[a[i]]!=-1&&ans[b[i]]!=-1&&ans[c[i]]==-1)
if((vis[(ans[a[i]]+ans[b[i]])%n])&&vis[(ans[a[i]]+ans[b[i]]+1)%n])return 0;
if(ans[a[i]]!=-1&&ans[b[i]]==-1&&ans[c[i]]!=-1)
if((vis[ans[c[i]]-ans[a[i]]])&&vis[ans[c[i]]+ans[a[i]]-1]&&vis[c[i]+n-ans[a[i]]]&&vis[c[i]+n-ans[a[i]]-1])return 0;
if(ans[a[i]]==-1&&ans[b[i]]!=-1&&ans[c[i]]!=-1)
if((vis[ans[c[i]]-ans[a[i]]])&&vis[ans[c[i]]+ans[a[i]]-1]&&vis[c[i]+n-ans[a[i]]]&&vis[c[i]+n-ans[a[i]]-1])return 0;
}
return 1;
}
void dfs(int x)
{
if(!_wzc())return;
if(x==n)
{
if(_wzc())
{
for(int i=0;i<n;i++)
printf("%d ",ans[i]);
exit(0);//搜到结果直接结束
}
}
for(int i=n-1;i>=0;i--)//反向搜
{
if(!vis[i])
{
vis[i]=1;
ans[sor[x]]=i;
dfs(x+1);
vis[i]=0;
ans[sor[x]]=-1;
}
}
return;
}
int main()
{
scanf("%d",&n);
scanf("%s%s%s",ch1,ch2,ch3);
for(int i=0;i<n;i++)
{
a[i]=ch1[i]-'A';
b[i]=ch2[i]-'A';
c[i]=ch3[i]-'A';
ans[i]=-1;
}
for(int i=n-1;i>=0;i--)//统计搜索顺序
{
if(!vis[a[i]])
{
vis[a[i]]=1;
sor[cnt++]=a[i];
}
if(!vis[b[i]])
{
vis[b[i]]=1;
sor[cnt++]=b[i];
}
if(!vis[c[i]])
{
vis[c[i]]=1;
sor[cnt++]=c[i];
}
}
memset(vis,0,sizeof(vis));
dfs(0);
return 0;
}

rp++

[BZOJ1902]:[NOIP2004]虫食算(搜索)的更多相关文章

  1. NOIP2004 虫食算

    描述 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一个简单的例子:43#9865#045+ 8468#6633= 44445506678其中#号代表 ...

  2. Luogu1092 NOIP2004虫食算(搜索+高斯消元)

    暴力枚举每一位是否进位,然后就可以高斯消元解出方程了.然而复杂度是O(2nn3),相当不靠谱. 考虑优化.注意到某一位进位情况的变化只会影响到方程的常数项,于是可以在最开始做一次高斯消元算出每个未知数 ...

  3. [Noip2004]虫食算 dfs

    搜索问题的关键:优秀的搜索策略以及行之有效的减枝 对于这道题我们阶乘搜肯定不行所以我们按位搜,我们对每一位的三个数进行赋值,然后判解. 对于此一类的搜索乘上一个几十的常数来减枝往往要比直接搜要快得多, ...

  4. P1092 虫食算[搜索]

    这个式子是是由\(A\sim A+N\)组成的,那么\(A\sim A+N\)就只能等于\(0\sim N-1\),因此我们每次对\(A\sim A+N\)的取值做一个新的排列,然后judge一下当前 ...

  5. NOIP 2004 虫食算题解

    问题 E: [Noip2004]虫食算 时间限制: 1 Sec  内存限制: 128 MB 题目描述 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一 ...

  6. [NOIP2004] 提高组 洛谷P1092 虫食算

    题目描述 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一个简单的例子: 43#9865#045 +8468#6633 44445509678 其中# ...

  7. 【NOIP2004】【CJOJ1703】【洛谷1092】虫食算

    题面 题目描述 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一个简单的例子: 43#9865#045 +8468#6633 44445509678 ...

  8. 【NOIP2004】虫食算

    Description 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一个简单的例子: 43#9865#045 +. 8468#6633 444455 ...

  9. 【搜索】$P1092$虫食算

    题目链接 首先,我们只考虑加法的虫食算.这里的加法是N进制加法,算式中三个数都有N位,允许有前导的0. 其次,虫子把所有的数都啃光了,我们只知道哪些数字是相同的,我们将相同的数字用相同的字母表示,不同 ...

随机推荐

  1. Windown Server 2008配置tomcat9虚拟路径

    一.用途 用于保存项目运产生的文件 二.步骤 1.修改conf\下的web.xml <!-- 找到listings将false改为true -->        <init-para ...

  2. C++的左值,右值,左值引用,右值引用

    参考大神链接: https://blog.csdn.net/u012198575/article/details/83142419 1.左值与右值 https://msdn.microsoft.com ...

  3. django 商城项目之购物车以及python中的一些redis命令

    最近在用django restframe框架做一个商城项目,有一个关于购物车的业务逻辑,是用cookie和redis存储的购物车信息,在这里记录一下. 完成一个商城项目,如果不做一个购物车,就是十分可 ...

  4. isinstance与issubclass,反射

    目录 isinstance与issubclass isinstance issubclass 反射 定义 反射在模块中的应用 内置方法 isinstance与issubclass isinstance ...

  5. django-xadmin使用

    django-xadmin使用基础环境为: PS:如下环境如需升级python则先升级python,然后安装django python3.6.4安装: http://www.cnblogs.com/c ...

  6. 07.AutoMapper 之列表和数组(Lists and Arrays)

    https://www.jianshu.com/p/419a3b7f12d5 列表和数组(Lists and Arrays) AutoMapper只需要配置元素类型的映射配置,不需要针对列表和数组进行 ...

  7. scrapy在settings中添加redis,可以实现断点续传

    DUPEFILTER_CLASS='scrapy_redis.dupefilter.RFPDupeFilter'SCHEDULER = 'scrapy_redis.scheduler.Schedule ...

  8. elementui 之el-pagination爬坑,属性pager-count的设定

    我想设置总页数为10页,页码条总是显示两个页码,其余省略号显示,我选择了pager-count,如下: <el-pagination @size-change="handleSizeC ...

  9. 十三、LaTex中的参考文献BibTex

    将默认文献工具设置为bibtex

  10. Java函数优雅之道

    https://www.cnblogs.com/amap_tech/p/11320171.html 导读 随着软件项目代码的日积月累,系统维护成本变得越来越高,是所有软件团队面临的共同问题.持续地优化 ...