P1092 虫食算

Posted lpf-666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1092 虫食算相关的知识,希望对你有一定的参考价值。

P1092 虫食算

DFS+剪枝

题意描述

有一个好好的算式突然被一只虫子给啃了,而且什么也没剩下,

然后我们莫名其妙的知道了哪些数是相同的,问各字母代表的数字,

数据保证有且仅有一组解,没了。

还看不懂的话,出门右手进传送门

算法分析

如果你很忙,请跳过下面3行

题意描述的比较简单,但也不是不能理解(语文不好)

看一看数据范围,发现n≤26,然后大喊三声:“爆搜!!!

过了15分钟,你又喊道:“妈妈我TLE啦!!!”

初步分析

首先设计状态,搜索的深度是确定的数的个数,当深度==n时表示确定了所有数(但并不保证答案正确)

显然如果爆搜你会TLE(2626是一个很有趣的数让你TLE的数),所以我们要考虑剪枝

同时,搜索的顺序也耐人寻味,难道是按照A,B,C······这样搜索吗?

还有,检测答案的方法又是什么?

综上,我们需要考虑三个问题:

  1. 怎么剪枝?
  2. 怎么钦定搜索顺序?
  3. 怎么检测答案?

深入探索

剪枝

算是重点吧。

第一,三个字符串长度都是n,很容易想到不能有进位

第二,首先我们看看这个 xx6xx

? + xx8xx

? ---------

? xx5xx

那么它是对是错?

  • 如果按照常理,6+8=14!=5或15,这是错的
  • 但如果上一位有进位,6+8+1=15,它又是合法的

所以有:如果某 (i) 位,满足 ((A[i]+B[i])%n!(=C[i])) && ((A[i]+B[i]+1))%n!(=C[i])

根据上面的分析,这种状态肯定不对,直接return

搜索顺序

小学生都知道的:从低位到高位搜(具体看代码)

检测答案

从低位到高位跑一遍等式即可(具体看代码)

代码实现

#include<algorithm>
 #include<cstdio>
 #include<iostream>
 #include<cstring>
 #include<cmath>
 using namespace std;

int n,a[30],b[30],c[30];
 int num[30],id[30],sum=0;
 char aa[30],bb[30],cc[30];
 bool use[30];

void Get(int x){          
     if(!use[x]){
         use[x]=true;
         id[sum++]=x;                               <————搜索顺序预处理
     }
     return;
 }

bool check(){
     for(int i=n,p=0;i>=1;i--){
         int A=num[a[i]],B=num[b[i]],C=num[c[i]];
         if((A+B+p)%n!=C) return false;                  <————检测答案
         p=(A+B+p)/n;
      }
      return true;
 }

void print(){
     for(int i=1;i<=n;i++) printf("%d ",num[i]);
     exit(0);
 }

bool cut_down(){
     if(num[a[1]]+num[b[1]]>=n) return true;
     for(int i=n;i>=1;i--){
         int A=num[a[i]],B=num[b[i]],C=num[c[i]];          <————剪枝
         if(A==-1||B==-1||C==-1) continue;
         if((A+B)%n!=C&&(A+B+1)%n!=C) return true;
     }
     return false;
 }

void dfs(int x){
     //for(int i=1;i<=n;i++) printf("%d ",num[i]);
     //printf("
");
     if(cut_down()) return;
     if(x==n){
         if(check()) print();
         return;
     }
     
     for(int i=n-1;i>=0;i--){
         if(!use[i]){
             num[id[x]]=i;
             use[i]=true;
             dfs(x+1);
             num[id[x]]=-1;
             use[i]=false;
         }
     }
     return;
 }

int main(){
     scanf("%d",&n);
     cin>>aa>>bb>>cc;
     for(int i=1;i<=n;i++){
         a[i]=aa[i-1]-'A'+1;
         b[i]=bb[i-1]-'A'+1;
         c[i]=cc[i-1]-'A'+1;
         num[i]=-1;
     }
     
     memset(use,false,sizeof(use));
     for(int i=n;i>=1;i--){
         Get(a[i]);Get(b[i]);Get(c[i]);
     }
     memset(use,false,sizeof(use));
     dfs(0);
     return 0;
 }

结语

Dfs+剪枝

以上是关于P1092 虫食算的主要内容,如果未能解决你的问题,请参考以下文章

洛谷P1092虫食算——深搜

P1092 虫食算

Luogu P1092 虫食算

P1092 虫食算

洛谷—— P1092 虫食算

洛谷 P1092 虫食算 Label:dfs