Description

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

43#9865#045

+. 8468#6633

44445509678

其中#号代表被虫子啃掉的数字。根据算式,我们很容易判断:第一行的两个数字分别是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个不同的字母分别代表的数字,使得该加法算式成立。输入数据保证有且仅有一组解

解题报告

搜索剪枝,实际上状态很少,考虑怎么样的搜索顺序使得状态最少,肯定是按位枚举,把确定的字母标记一下,并且标记哪些数字被用过,产生矛盾就停止搜索,注意回溯

另外就是判断每一位的等式是否成立,注意进位的问题,递归时记录即可

本人的实现很复杂,代码可以参考其他博客,大概方法是把三个串按dfs枚举顺序弄成一个序列,就可以避免8种讨论了

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int N=31;
char S[N];int n,a[N],b[N],c[N],val[N];bool d[N];
il void dfs(int x,int ad){
if(x==0){
if(!ad){
for(int i=1;i<=n;i++)printf("%d ",val[i]);
exit(0);
}
return ;
}
RG int i1=a[x],i2=b[x],i3=c[x],j,i;
if(val[i1]!=-1 && val[i2]!=-1 && val[i3]!=-1){
if((val[i1]+val[i2]+ad)%n==val[i3])
dfs(x-1,val[i1]+val[i2]+ad>=n);
return ;
}
if(val[i1]==-1 && val[i2]==-1 && val[i3]==-1){
if(i1!=i2)
{
for(i=n-1;i>=0;i--){
if(d[i])continue;
d[i]=true;val[i1]=i;
for(j=n-1;j>=0;j--){
if(d[j])continue;
val[i2]=j;val[i3]=(i+j+ad);d[j]=true;
if(val[i3]>=n)val[i3]-=n;
if(!d[val[i3]])
d[val[i3]]=1,dfs(x-1,i+j+ad>=n),d[val[i3]]=0;
else if(i3==i1 || i3==i2)dfs(x-1,i+j+ad>=n);
val[i2]=-1;val[i3]=-1;d[j]=false;
}
d[i]=false;val[i1]=-1;
}
}
else{
for(i=n-1;i>=0;i--){
if(d[i])continue;
d[i]=true;val[i1]=val[i2]=i;
val[i3]=(i+i+ad)%n;
if(!d[val[i3]])
d[val[i3]]=1,dfs(x-1,i+i+ad>=n),d[val[i3]]=0;
else if(i3==i1 || i3==i2)dfs(x-1,i+i+ad>=n);
d[i]=false;val[i1]=val[i2]=-1;
}
}
return ;
}
else if(val[i3]==-1){
if(val[i1]!=-1 && val[i2]!=-1){
val[i3]=(val[i1]+val[i2]+ad)%n;
if(!d[val[i3]])
d[val[i3]]=1,dfs(x-1,val[i1]+val[i2]+ad>=n),d[val[i3]]=0;
else if(i3==i1 || i3==i2)dfs(x-1,val[i1]+val[i2]+ad>=n);
val[i3]=-1;
return ;
}
if(val[i2]==-1)swap(i1,i2);
for(i=n-1;i>=0;i--){
if(d[i])continue;
val[i1]=i;d[i]=true;
val[i3]=(i+val[i2]+ad)%n;
if(!d[val[i3]])
d[val[i3]]=1,dfs(x-1,i+val[i2]+ad>=n),d[val[i3]]=0;
else if(i1==i3 || i3==i2)dfs(x-1,i+val[i2]+ad>=n);
val[i1]=-1;val[i3]=-1;
d[i]=false;
}
return ;
} if(val[i3]!=-1){
if(val[i1]==-1 && val[i2]==-1){
for(i=n-1;i>=0;i--){
if(d[i])continue;
val[i1]=i;d[i]=true;
if(i+ad<=val[i3])val[i2]=val[i3]-i-ad;
else val[i2]=val[i3]+n-i-ad;
if(!d[val[i2]])
d[val[i2]]=1,dfs(x-1,val[i1]+val[i2]+ad>=n),d[val[i2]]=0;
else if(i2==i1 || i2==i3)dfs(x-1,val[i1]+val[i2]+ad>=n);
val[i1]=-1;val[i2]=-1;
d[i]=false;
}
}
else{
if(val[i2]==-1)swap(i1,i2);
if(val[i2]+ad<=val[i3])val[i1]=val[i3]-val[i2]-ad;
else val[i1]=val[i3]+n-val[i2]-ad;
if(!d[val[i1]])
d[val[i1]]=1,dfs(x-1,val[i1]+val[i2]+ad>=n),d[val[i1]]=0;
else if(i1==i3 || i1==i2)dfs(x-1,val[i1]+val[i2]+ad>=n);
val[i1]=-1;
}
}
}
void work()
{
scanf("%d",&n);
scanf("%s",S+1);memset(val,-1,sizeof(val));
for(int i=1;i<=n;i++)a[i]=S[i]-'A'+1;
scanf("%s",S+1);
for(int i=1;i<=n;i++)b[i]=S[i]-'A'+1;
scanf("%s",S+1);
for(int i=1;i<=n;i++)c[i]=S[i]-'A'+1;
dfs(n,0);
} int main()
{
work();
return 0;
}

【NOIP2004】虫食算的更多相关文章

  1. NOIP2004 虫食算

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

  2. [BZOJ1902]:[NOIP2004]虫食算(搜索)

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

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

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

  4. [Noip2004]虫食算 dfs

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

  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. 洛谷 P1092 虫食算 Label:dfs

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

  9. Luogu P1092 虫食算

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

随机推荐

  1. Tornado 网站demo 二

    连接数据库 methods 中建立一个文件 db.py 分别建立起连接对象和游标对象 #!/usr/bin/env Python # coding=utf-8 import pymysql conn ...

  2. 【iOS】Swift LAZY 修饰符和 LAZY 方法

    延时加载或者说延时初始化是很常用的优化方法,在构建和生成新的对象的时候,内存分配会在运行时耗费不少时间,如果有一些对象的属性和内容非常复杂的话,这个时间更是不可忽略.另外,有些情况下我们并不会立即用到 ...

  3. SCOI2010 序列操作

    2421 序列操作 http://codevs.cn/problem/2421/ 2010年省队选拔赛四川   题目描述 Description lxhgww最近收到了一个01序列,序列里面包含了n个 ...

  4. Ajax 的onreadystatechange事件注意事项.

    <script type="text/javascript"> function createXHR() { var request = false; try { re ...

  5. phalcon框架命名空间

    命名空间第一影像就是实际上就相当宏定义,就是需要把一个很长的带有路径的类文件指定一个空间,然后就可直接用简单简写模式 当然如果是外部文件需要首先引入外部文件,如果不引入外部文件还是会报错.一般最会出错 ...

  6. 从PRISM开始学WPF(八)導航Navigation?

    0x6Navigation Basic Navigation Prism中的Navigation提供了一种类似导航的功能,他可以根据用户的输入,来刷新UI. 先看一个最简单的例子,通过按钮来导航到一个 ...

  7. Python系列之 - 面向对象(1)

    python是一门面向对象的编程语言,python中的一切均是对象. 有对象就提到类,对象和类就像是儿子和老子的关系,是不可分的一对. 什么是类     类就是具有一些共同特性的事物的统称.好比人类, ...

  8. POJ-1135 Domino Effect---最短路Dijk

    题目链接: https://vjudge.net/problem/POJ-1135 题目大意: 有N个关键的多米诺骨牌,这些牌通过一些路径相连接,这些路径是由一排其他骨牌构成的.已知每一条路径上的骨牌 ...

  9. html如何实现的

    超文本标记语言是标准通用标记语言下的一个应用,也是一种规范,一种标准,它通过标记符号来标记要显示的网页中的各个部分.网页文件本身是一种文本文件,通过在文本文件中添加标记符,可以告诉浏览器如何显示其中的 ...

  10. ST-LINK V2 DIY笔记(一)

    最近一段时间调试STM32板子的时候,都是用JLINK+杜邦线,或者拿官方板子当STLINK用,可以用,但是体积比较大,有时候觉得比较麻烦.正好前一阵手头项目少,就想DIY一个STLINK. 图是网上 ...