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 }
注释已经解释的很详细了(确实)

浙公网安备 33010602011771号