题目传送门

这道题是一道经久不衰的搜索题目,但是开始做的时候我没什么思路==。初始值-1 输出格式

\(naive\)想法

从右往左依次尝试填充数字,把算式当做一个3行\(n\)列的网格。(什么?你问为什么是从右往左?大概是人类习惯吧\(qwq\)),然后需要头脑清晰的分类讨论,对搜到第三行字符串时要特别注意。

具体的分类讨论:当前位置是否已经填了(\(*2\)),判断当前行是不是第三行(\(*2\))。

\(80\)分代码:

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. using namespace std;
  5. int n;
  6. int num[30];
  7. bool vis[30];
  8. char st[4][30];
  9. void dfs(int y,int x,int hi)
  10. {//列 行 进位数
  11. if(y==0)
  12. {
  13. if(hi!=0) return ;
  14. for(int i=1;i<=n-1;i++) printf("%d ",num[i]);
  15. printf("%d",num[n]);
  16. exit(0);
  17. }
  18. if(num[st[x][y]-'A'+1]!=-1)
  19. {
  20. if(x!=3) dfs(y,x+1,hi);
  21. //当前位已经被填 向下搜索
  22. else
  23. {//在第三行时能保证当前列的第一行&第二行已经临时确定
  24. int w=num[st[1][y]-'A'+1]+num[st[2][y]-'A'+1]+hi;
  25. if(w%n!=num[st[3][y]-'A'+1]) return ;
  26. dfs(y-1,1,w/n);
  27. //向左边推进
  28. }
  29. }
  30. else
  31. {
  32. for(int i=0;i<=n-1;i++)
  33. if(!vis[i])
  34. {
  35. if(x==3)
  36. {//搜到这里的时候保证第一行第二行都已经搜过
  37. int w=num[st[1][y]-'A'+1]+num[st[2][y]-'A'+1]+hi;
  38. if(w%n!=i) continue;
  39. vis[i]=1;num[st[3][y]-'A'+1]=i;
  40. dfs(y-1,1,w/n);
  41. vis[i]=0;num[st[3][y]-'A'+1]=-1;
  42. }
  43. else
  44. {
  45. vis[i]=1;num[st[x][y]-'A'+1]=i;
  46. dfs(y,x+1,hi);
  47. vis[i]=0;num[st[x][y]-'A'+1]=-1;
  48. }
  49. }
  50. }
  51. }
  52. int main()
  53. {
  54. scanf("%d",&n);
  55. scanf("%s",st[1]+1);
  56. scanf("%s",st[2]+1);
  57. scanf("%s",st[3]+1);
  58. memset(num,-1,sizeof(num));
  59. dfs(n,1,0);
  60. return 0;
  61. }

强力剪枝

但是\(T\)了两个点,我们怎么办呢?可以加入两个强力剪枝。

①:在尝试放新的数字时,我们可能习惯从\(0\)~\(n-1\)放,但是如果从\(n-1\)到\(0\)放的话会快很多。为什么?小的数字更容易进到深层,如果不合法就会浪费很多时间;而大的数字容易引起回溯,但是不会引起结果的改变,所以这个剪枝可行。

②:我们真的要在状态都确定结束的时候才判断它是否合法吗?就不能边搜边判嘛?确定新数的时候我们肯定是保证它在当前状态下(眼前)是合法的,但是即使每次都合法,组在一起仍有可能不合法,因此,我们边搜边判。具体地说,就是每次搜的时候,看自己左边的列如果三行都确定的话,就检查下他们是否合法,这个剪枝还是很强的。

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. using namespace std;
  5. int n;
  6. int num[30];
  7. bool vis[30];
  8. char st[4][30];
  9. void dfs(int y,int x,int hi)
  10. {
  11. if(y==0)
  12. {
  13. if(hi!=0) return ;
  14. for(int i=1;i<=n-1;i++) printf("%d ",num[i]);
  15. printf("%d",num[n]);
  16. exit(0);
  17. }
  18. for(int i=y-1;i>=1;i--)
  19. {
  20. int a=num[st[1][i]-'A'+1];
  21. int b=num[st[2][i]-'A'+1];
  22. int c=num[st[3][i]-'A'+1];
  23. if(a==-1||b==-1||c==-1) continue ;
  24. if((a+b)%n!=c&&(a+b+1)%n!=c) return ;
  25. }
  26. if(num[st[x][y]-'A'+1]!=-1)
  27. {
  28. if(x!=3) dfs(y,x+1,hi);
  29. else
  30. {
  31. int w=num[st[1][y]-'A'+1]+num[st[2][y]-'A'+1]+hi;
  32. if(w%n!=num[st[3][y]-'A'+1]) return ;
  33. dfs(y-1,1,w/n);
  34. }
  35. }
  36. else
  37. {
  38. for(int i=n-1;i>=0;i--)
  39. if(!vis[i])
  40. {
  41. if(x==3)
  42. {
  43. int w=num[st[1][y]-'A'+1]+num[st[2][y]-'A'+1]+hi;
  44. if(w%n!=i) continue;
  45. vis[i]=1;num[st[3][y]-'A'+1]=i;
  46. dfs(y-1,1,w/n);
  47. vis[i]=0;num[st[3][y]-'A'+1]=-1;
  48. }
  49. else
  50. {
  51. vis[i]=1;num[st[x][y]-'A'+1]=i;
  52. dfs(y,x+1,hi);
  53. vis[i]=0;num[st[x][y]-'A'+1]=-1;
  54. }
  55. }
  56. }
  57. }
  58. int main()
  59. {
  60. scanf("%d",&n);
  61. scanf("%s",st[1]+1);
  62. scanf("%s",st[2]+1);
  63. scanf("%s",st[3]+1);
  64. memset(num,-1,sizeof(num));
  65. dfs(n,1,0);
  66. return 0;
  67. }

另一些细节

因为赋数字是从\(0\)到\(n-1\)的,所以初始值都要设成\(-1\)。回溯的时候也别习惯回成\(0\)。

注意下输出格式。

Luogu P1092 虫食算【搜索/剪枝】 By cellur925的更多相关文章

  1. Luogu P1092 虫食算(枚举+剪枝)

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

  2. Luogu P1092 虫食算

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

  3. P1092 虫食算[搜索]

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

  4. Luogu P1092 虫食算 爆搜

    心路历程:震惊,我竟然得了$90$分!!...康康数据...奥..(忽然有了邪恶的卡数据的想法) 于是把$for(int \space i=0;i<n;++i)$改成了$for(int \spa ...

  5. P1092 虫食算 题解(搜索)

    题目链接 P1092 虫食算 解题思路 好题啊!这个搜索好难写...... 大概是要考虑进位和考虑使用过某个数字这两个东西,但就很容易出错...... 首先这个从后往前搜比较好想,按照从后往前出现的顺 ...

  6. 【题解】 P1092虫食算

    [题解]P1092 虫食算 老题了,很经典. 用到了一些搜索套路. 可行性剪枝,劣者靠后,随机化,\(etc......\) 搜索设参也很有技巧,设一个\(adjustment\)参数可以很方便地在两 ...

  7. 洛谷P1092 虫食算

    P1092 虫食算 题目描述 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一个简单的例子: http://paste.ubuntu.com/2544 ...

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

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

  9. 洛谷 P1092 虫食算 Label:dfs

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

随机推荐

  1. 九度OJ 1090:路径打印 (树、DFS)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:1704 解决:314 题目描述: 给你一串路径,譬如: a\b\c a\d\e b\cst d\ 你把这些路径中蕴含的目录结构给画出来,子目 ...

  2. ElasticSearch(十一)批量CURD bulk

    1.bulk语法 POST /_bulk { "delete": { "_index": "test_index", "_type ...

  3. MySql in子句 效率低下优化(亲测有效,从200秒变1秒)

    MySql in子句 效率低下优化 背景: 更新一张表中的某些记录值,更新条件来自另一张含有200多万记录的表,效率极其低下,耗时高达几分钟. update clear_res set candele ...

  4. bluebird-api简介及demo

    var Promise = require("bluebird"); var fs = require("fs"); //方法Promise化 var read ...

  5. access 连接数据库

    前提条件 如果没有安装office的话,需要安装引擎 安装了office就不用安装引擎 连接数据库 Dim plMydb As Microsoft.Office.Interop.Access.Dao. ...

  6. uni-app 创建的第一个应用

    本人微信公众号:前端修炼之路,欢迎关注 背景介绍 经过上一篇文章uni-app官方教程学习手记的学习之后,我就着手做这个项目了. 目前已经初步搭出了整体的框架,秉着取之于社会,回馈于社会的原则,我将这 ...

  7. 基于BASYS2的VHDL程序——数字钟(最终版)

    转载请注明原地址:http://www.cnblogs.com/connorzx/p/3674178.html 调时电路正常工作.一切正常.发现做FPGA还是得从数电的思路思考,设置一个预置使能端,预 ...

  8. 恶心的struts标签,等我毕业设计弄完了,瞧我怎么收拾你。

    1.从java action中到页面中获取变量值的struts标签 获取从bean中定义的对象中属性的值: <s:property value="#request.cardTo.acc ...

  9. the art of seo(chapter one)

    preface:Andy Johns (@ibringtraffic):growth strategist@Wealthfront ***1.Search Reflecting Consciousne ...

  10. codeforces 702D D. Road to Post Office(数学)

    题目链接: D. Road to Post Office time limit per test 1 second memory limit per test 256 megabytes input ...