标签:cpp class ++ str 顺序 探索 一个 ace cut
DFS+剪枝
有一个好好的算式突然被一只虫子给啃了,而且什么也没剩下,
然后我们莫名其妙的知道了哪些数是相同的,问各字母代表的数字,
数据保证有且仅有一组解,没了。
还看不懂的话,出门右手进传送门
如果你很忙,请跳过下面3行
题意描述的比较简单,但也不是不能理解(语文不好)
看一看数据范围,发现n≤26,然后大喊三声:“爆搜!!!”
过了15分钟,你又喊道:“妈妈我TLE啦!!!”
首先设计状态,搜索的深度是确定的数的个数,当深度==n时表示确定了所有数(但并不保证答案正确)
显然如果爆搜你会TLE(2626是一个很有趣的数让你TLE的数),所以我们要考虑剪枝,
同时,搜索的顺序也耐人寻味,难道是按照A,B,C······这样搜索吗?
还有,检测答案的方法又是什么?
综上,我们需要考虑三个问题:
算是重点吧。
第一,三个字符串长度都是n,很容易想到不能有进位。
第二,首先我们看看这个 xx6xx
? + xx8xx
? ---------
? xx5xx
那么它是对是错?
所以有:如果某 \(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+剪枝
标签:cpp class ++ str 顺序 探索 一个 ace cut
原文地址:https://www.cnblogs.com/lpf-666/p/12436144.html