题目传送门


题目描述

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

来看一个简单的例子:

  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. html之input

    <input>在w3c中解释的是用于搜集用户的信息 它其实就是一个输入框,根据type的不同这个框可以用作不同的功能可以输入一个文本,可以定义一个按钮什么的. 属性type一些值的介绍 1 ...

  2. mysql 聚合函数(2)

    平均 svg select avg(sal + IFNULL(comm,0)) as avg_sal from t_emp 总和 sum select sum(sal + IFNULL(comm,0) ...

  3. Codeforces 1215F. Radio Stations

    传送门 题目看一半:"woc 裸的 $2-sat$ 白给??" 看完以后:"...???" 如果没有 $f$ 的限制,那就是个白给的 $2-sat$ 问题,但是 ...

  4. HBASE学习笔记(四)

    这两天把要前几天的知识点回顾一下,接下来我会用自己对知识点的理解来写一些东西 一.知识点回顾 1.hbase集群启动:$>start-hbase.sh ===>hbase-daemon.s ...

  5. npm切换淘宝镜像源

    npm 切换到淘宝源地址默认的npm下载地址:http://www.npmjs.org/淘宝npm镜像的地址:https://npm.taobao.org/ 临时使用淘宝源npm --registry ...

  6. MySQL第三讲 一一一一 视图、触发器、函数、存储过程

    1. 视图 1.1 视图前戏 我们之前讲有,临时表的概念. 现在我们创建一个临时表:select * from (select * from tb1 where id between 10 and 1 ...

  7. Django 解决跨域问题(写入到中间件中)

    class MiddlewareMixin(object): def __init__(self, get_response=None): self.get_response = get_respon ...

  8. 引用vector里的元素被删除后,引用会怎么样?

    引用的定义不多说,直接看做变量的别名就可以了.有一天写着写着代码,突然想到,如果对vector里某个元素设置引用后,将这个元素从vector里删除会怎么样?我思考了下,认为那个元素会被删除,但是引用还 ...

  9. 七、设备驱动中的阻塞与非阻塞 IO(一)

    7.1 阻塞与非阻塞 IO 阻塞操作是指在执行设备操作的时候,若不能获取资源,则挂起进程直到满足可操作的条件后再进行操作.被挂起的进程进入睡眠状态,被从调度器的运行队列移走,直到等待的条件被满足. 非 ...

  10. u-boot include目录 gd_t结构体 如何关联芯片指定的目录

    1 u-boot /u-boot-2018.07-fmxx/include/config.h /* Automatically generated - do not edit */#define CO ...