1. P1008 [NOIP1998 普及组] 三连击

题目描述

将 1,2,…,9 共 9个数分成 3 组,分别组成 3 个三位数,且使这 3个三位数构成 1:2:3的比例,试求出所有满足条件的 3个三位数。

输入

输出

若干行,每行 3个数字。按照每行第 1 个数字升序排列。

 

分析:

1.开一个ans数组(类似于桶排序)存放1-9是否被使用

从第一个数123开始枚举,通过*2*3判断第二个第三个数是否符合题意

(中间会伴随着拆数与合并的过程)

 

2.全排列后判断*2*3是否正确(大人写法)

 

 

 

代码1(我的写法)(太麻烦且逻辑性不强)

 1 #include<iostream>
 2 using namespace std;
 3 int ans[15];
 4 int a,b,c;
 5 bool pdd(int n)
 6 {
 7     int x, y, z;
 8     x=n/100;
 9     y=n/10%10;
10     z=n%10;
11     if(ans[x]==0&&ans[y]==0&&ans[z]==0)
12     {
13         ans[x]=1;ans[y]=1;ans[z]=1;
14         return 1;
15     }
16     return 0;
17 }
18 int main()
19 {
21     for(int i=1;i<=3;i++)//!!!!!!!
22     {
23         ans[i]=1;
24         for(int j=1;j<=9;j++)
25         {
26             if(ans[j]==1) continue;
27             else ans[j]=1;
28             for(int k=1;k<=9;k++)
29             {
30                 if(ans[k]==1) continue;
31                 ans[k]=1;
32                 a=100*i+10*j+k;
33                 b=a*2;
34                 c=a*3;
35                 if(pdd(b)==1)
36                 {
37                     if(pdd(c)==1)
38                         cout<<a<<" "<<b<<" "<<c<<endl;                        
39                 }
40                 for(int m=1;m<=9;m++) ans[m]=0;
41                 ans[i]=1;ans[j]=1;
42                 ans[k]=0;
43             }
44             ans[j]=0;
45         }
46         ans[i]=0;
47      } 
50     return 0;
51  } 

错因:

回溯不完全(40到41行)

总结:

1.搜索回溯时,要详细的列出哪些变量用过,凡是用过都需要考虑

(特别是在函数里面定义的)

学会拆数(高精度要用)

    while(x!=0)
    {
        int num=x%10;
        x/=10;
        ans[num]++;
    }

 

 

代码2(老师写法)

 1 #include<iostream>
 2 using namespace std;
 3 int ans[15];
 4 int a,b,c;
 5 int chai(int x)
 6 {
 7     while(x!=0)
 8     {
 9         int num=x%10;
10         x/=10;
11         ans[num]++;
12     }  
14 }
15 int main()
16 {
17     bool t=0;
18     for(int i=1;i<=9;i++)
19     {
20         for(int j=1;j<=9;j++)
21         {
22             for(int k=1;k<=9;k++)
23             {
24                 a=100*i+10*j+k;
25                 b=a*2;
26                 c=a*3;
27                 t=0;
28                 chai(a);
29                 chai(b);
30                 chai(c);
31                 for(int i=1;i<=9;i++)
32                     if(ans[i]!=1)t=1;
33                 if(t==0) cout<<a<<" "<<b<<" "<<c<<endl;
34                 for(int i=1;i<=9;i++)
35                     ans[i]=0;
36             }
37         }
38      } 
41     return 0;
42  } 

 优化与改进:

1.bool改做int类型,通过++控制带来更大的自由发挥空间

2.标记和回溯的过程放在一起而不拆分(在int判断的前提下)

  使得回溯更加简洁,逻辑性更强更好排错

 

代码3(全排列fys写法)

 1 #include<iostream>
 2 #include<vector>
 3 #include<algorithm>
 4 //DFS 
 5 bool vis[20];//深搜(记忆化+回溯)广搜(记忆化不回溯)都有 
 6 int queue[50];
 7 int answers[500];
 8 int cnt=0;
 9 void search(int x)//x代表位数 
10 {
11     for(int i=1;i<=9;i++)//i是位数上的数字 
12     {
13         if(!vis[i])
14         {
15             vis[i]=1;//桶,此全排列中是否用过这个数字 
16             queue[x]=i;//这个是真正的排列组合 
17                       //x是位数,i是位数上的数字 (10,12行) 
18             if(x>1)
19                 search(x-1);//从后往前寻找                
20              else//已有一组答案被生成 ,筛选符合题意的解 
21              {
22                  int num1=queue[1]*100+queue[2]*10+queue[3];
23                  int num2=queue[4]*100+queue[5]*10+queue[6];
24                  int num3=queue[7]*100+queue[8]*10+queue[9];
25                  if((num2==num1*2)&&(num3==num1*3))
26                      answers[cnt++]=num1;//cnt为目前解的个数 
27              }
28             vis[i]=0;//对应20行,出search后才回溯!! 
29                     //模拟出栈入栈 
30         }
31     }
32 }//BFS生成全排列的代码 
33 
34 int main()
35 {
36     search(9);
37     sort(answers,answers+cnt);
38     for(int i=0;i<cnt;i++)
39         cout<<answers[i]<<" "<<answers[i]*2<<" "<<answers[i]*3<<std::endl;
40 
41 }

注释已经解释的很详细了(确实)

 

posted @ 2022-08-21 20:07  要不要吃哈密瓜  阅读(107)  评论(0)    收藏  举报