码迷,mamicode.com
首页 > 其他好文 > 详细

P1092 虫食算

时间:2020-03-07 19:10:46      阅读:77      评论:0      收藏:0      [点我收藏+]

标签:cpp   class   ++   str   顺序   探索   一个   ace   cut   

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("\n");
     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 虫食算

标签:cpp   class   ++   str   顺序   探索   一个   ace   cut   

原文地址:https://www.cnblogs.com/lpf-666/p/12436144.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!