[洛谷P1092][题解]虫食算

我不是题目

1.暴力枚举全排列,30分,代码不放了

2.思考如何剪枝

剪枝一:由于是竖式加法,所以可以枚举已经知道的部分,如果矛盾就退出

例:

xx1xx

xx1xx

-------

xx4xx

显然是错的

剪枝二:如果按字母顺序枚举大概率有数没有枚举过,太分散

考虑从后往前枚举,碰到哪个先枚举哪个

至此,已100分。

Code:

 1 #include
 2 #define rint register int
 3 #define debug cout<<"AJH AK IOI!!!"< 4 using namespace std;
 5 
 6 int n,tr[100];
 7 string a,b,s;
 8 bool vis[30];
 9 int pmt[30],cnt,used[30];
10 
11 inline int id(char a){return a-'A'+1;}
12 inline char ch(int a){return a+'A'-1;}
13 
14 inline void Check(){
15     int cr=0;
16     for(rint i=n-1;i>=0;i--){
17         int sum=tr[a[i]]+tr[b[i]]+cr;
18         //检验答案 
19         if(sum%n!=tr[s[i]])return;
20         cr=sum/n;
21     }
22     cout<'A'];
23     for(rint i='A'+1;i<='A'+n-1;i++)cout<<" "<<tr[i];
24     cout<<endl;
25     exit(0);
26 }
27 
28 inline bool Prune(){
29     for(int i=n-1;i>=0;i--){
30         //有没搜过的就跳 
31         int ta=tr[a[i]],tb=tr[b[i]],ts=tr[s[i]];
32         if(ta==-1||tb==-1||ts==-1)continue;
33         //剪枝一:如果答案错误就返回0 
34         if((ta+tb)%n!=ts){
35             if((ta+tb+1)%n!=ts)return 0;
36         }
37     }
38     return 1;
39 }
40 
41 void DFS(int now){
42     if(now>n){
43         Check();
44         return;
45     }
46     //开始深搜啦~ 
47     for(rint i=n-1;i>=0;i--){
48         if(vis[i])continue;
49         tr[ch(pmt[now])]=i;//调整排列 
50         if(Prune()){
51             vis[i]=1;
52             DFS(now+1);
53             vis[i]=0;
54         }
55     }
56     tr[ch(pmt[now])]=-1;//别忘了标回去 
57 }
58 
59 int main(){
60     cin>>n>>a>>b>>s;
61     memset(tr,-1,sizeof(tr));
62     //剪枝二:调整搜索顺序 
63     for(rint i=n-1;i>=0;i--){
64         rint ai=id(a[i]);
65         rint bi=id(b[i]);
66         rint si=id(s[i]);
67         //先搜后面的 
68         if(!used[ai])pmt[++cnt]=ai,used[ai]=1;
69         if(!used[bi])pmt[++cnt]=bi,used[bi]=1;
70         if(!used[si])pmt[++cnt]=si,used[si]=1;
71     }
72     
73     DFS(1);
74     return 0;//功德圆满 
75 }

你可能感兴趣的:([洛谷P1092][题解]虫食算)