[BZOJ1902]:[NOIP2004]虫食算(搜索)
题目传送门
题目描述
所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母。
来看一个简单的例子:
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]虫食算(搜索)的更多相关文章
- NOIP2004 虫食算
描述 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一个简单的例子:43#9865#045+ 8468#6633= 44445506678其中#号代表 ...
- Luogu1092 NOIP2004虫食算(搜索+高斯消元)
暴力枚举每一位是否进位,然后就可以高斯消元解出方程了.然而复杂度是O(2nn3),相当不靠谱. 考虑优化.注意到某一位进位情况的变化只会影响到方程的常数项,于是可以在最开始做一次高斯消元算出每个未知数 ...
- [Noip2004]虫食算 dfs
搜索问题的关键:优秀的搜索策略以及行之有效的减枝 对于这道题我们阶乘搜肯定不行所以我们按位搜,我们对每一位的三个数进行赋值,然后判解. 对于此一类的搜索乘上一个几十的常数来减枝往往要比直接搜要快得多, ...
- P1092 虫食算[搜索]
这个式子是是由\(A\sim A+N\)组成的,那么\(A\sim A+N\)就只能等于\(0\sim N-1\),因此我们每次对\(A\sim A+N\)的取值做一个新的排列,然后judge一下当前 ...
- NOIP 2004 虫食算题解
问题 E: [Noip2004]虫食算 时间限制: 1 Sec 内存限制: 128 MB 题目描述 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一 ...
- [NOIP2004] 提高组 洛谷P1092 虫食算
题目描述 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一个简单的例子: 43#9865#045 +8468#6633 44445509678 其中# ...
- 【NOIP2004】【CJOJ1703】【洛谷1092】虫食算
题面 题目描述 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一个简单的例子: 43#9865#045 +8468#6633 44445509678 ...
- 【NOIP2004】虫食算
Description 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一个简单的例子: 43#9865#045 +. 8468#6633 444455 ...
- 【搜索】$P1092$虫食算
题目链接 首先,我们只考虑加法的虫食算.这里的加法是N进制加法,算式中三个数都有N位,允许有前导的0. 其次,虫子把所有的数都啃光了,我们只知道哪些数字是相同的,我们将相同的数字用相同的字母表示,不同 ...
随机推荐
- [gym101981M][2018ICPC南京M题]Mediocre String Problem
题目链接 题目大意是问在$S$串中找区间$[i,j]$,在$T$串中找位置$k$,使得$S[i,j]$和$T[1,k]$可以组成回文串,并且$j-i+1>k$,求这样的三元组$(i,j,k)$的 ...
- <<C++ Primer>> 术语表 (总) (待补充)
术语表 目录 第 1 章 开始 第 I 部分 C++基础 第 2 章 变量和基本类型 第 3 章 字符串, 向量和数组 第 4 章 表达式 第 5 章 语句 第 6 章 函数 第 7 章 类 第 II ...
- python requests的content和text方法的区别【转】
requests对象的get和post方法都会返回一个Response对象,这个对象里面存的是服务器返回的所有信息,包括响应头,响应状态码等.其中返回的网页部分会存在.content和.text两个对 ...
- python之网络部分
1.C/S B/S架构 C: client端 B: browse 浏览器 S: server端 C/S架构: 基于客户端与服务端之间的通信 QQ, 游戏,皮皮虾, 快手,抖音. 优点: 个性化 ...
- kafka 教程(四)-原理进阶
kafka 最初由 Linkedin 公司开发,是一个 分布式.支持分区.多副本的,基于 zookeeper 协调的分布式发布订阅消息系统,该公司在 2010 年将 kafka 贡献给 apache ...
- linux VMware 提供的网络连接有 5 种详细讲述
VMware 提供的网络连接有 5 种,分别是"桥接模式"."NAT 模式"."仅主机模式"."自定义"和"L ...
- 【iOS】正則表達式抓取网页数据制作小词典
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/xn4545945/article/details/37684127 应用程序不一定要自己去提供数据. ...
- mybatis工作原理及实现
对数据库的连接 使用时就创建连接,不使用就立即释放,对数据库进行频繁连接开启和关闭,造成数据库的资源浪费,影响数据库的性能: 解决办法:使用数据库连接池,管理数据库的连接. 2 将sql语句硬编码到j ...
- vue video.js使用
插件github地址:https://github.com/videojs/video.js 这边做一个切换视频vue url的解决记录 this.$nextTick(() => { let u ...
- css阴影——box-shadow
1.语法 box-shadow: h-shadow v-shadow blur spread color inset; box-shadow: 水平阴影 垂直阴影 模糊距离 阴影大小 阴影 ...