三连击问题
1.题目
题目背景
本题为提交答案题,您可以写程序或手算在本机上算出答案后,直接提交答案文本,也可提交答案生成程序。
题目描述
将1,2,⋯,9共9个数分成3组,分别组成3个三位数,且使这3个三位数构成1:2:3的比例,试求出所有满足条件的3个三位数。
输入格式
木有输入
输出格式
若干行,每行33个数字。按照每行第11个数字升序排列。
2.简单分析
初学C++,这道题是在洛谷上的训练营循环结构中。
这道题第一眼想到先取一个范围在123到987/3的数为m,剩下的两个数就分别是2m,3m。
然后考虑到题目要求组成三个三位数的单个数字必须是1到9且不能重复,很自然的想到要将三位数继续分解,采用最笨的方法,i=m/100;j=m%100/10;k=m%10,
诸如此类。
要判断不重复且全有,又无法直接做到,只能先排序,将三个数分解出来的9个单数存到数组再sort()一下,如果符合条件,一定为1到9,这样就可以遍历循环进行判断了a[i-1]是否与i相等。
又考虑直接if判断分不了情况,就在前面加一个flag=1,若a[i-1]!=i,flag=1,在外面判断flag=1则输出,这就是判断条件的主体。
最外面再按m的范围循环一下就好了。
代码如下
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int b[9] = { 0 };
int s;
for (s = 123; s <= 327; s++) {
int flag = 1;
b[0] = s / 100;
b[1] = s % 100 / 10;
b[2] = s % 10;
b[3] = 2 * s / 100;
b[4] = 2 * s % 100 / 10;
b[5] = 2 * s % 10;
b[6] = 3 * s / 100;
b[7] = 3 * s % 100 / 10;
b[8] = 3 * s % 10;/*注意此处要按这个格式输出,我一开始想用一个
双重循环,结果发现sort()只能排一维数组*/
sort(b, b + 9);
for (int i = 1; i <= 9; i++)
{
if (b[i - 1] != i)
flag = 0;
}
if (flag == 1)
printf("%d %d %d\n", s, 2 * s, 3 * s);
}
return 0;
}
3.反思优化
后来看到了两种简便的方法。
1.简单暴力
#include <stdio.h>
int main()
{
int a,b,c;
for(a=123;a<=333;a++)
{
b=a*2;
c=a*3;
if((a/100+a/10%10+a%10+b/100+b/10%10+b%10+c/100+c/10%10+c%10==1+2+3+4+5+6+7+8+9)&&((a/100)*(a/10%10)*(a%10)*(b/100)*(b/10%10)*(b%10)*(c/100)*(c/10%10)*(c%10)==(1)*(2)*(3)*(4)*(5)*(6)*(7)*(8)*(9)))
printf("%d %d %d\n",a,b,c);
}
return 0;
}
来源于 https://www.luogu.org/problemnew/solution/P1008.
作者 WilliamEdward
分解方法一样,但判断直接以1到9的积和和判断,这样就不用存到数组再排序判断了。
2.巧妙转化
#include<cstdio>
#include<cstring>
int i,j,v;bool a[10];//ai表示第i个数已经用过了
int main()
{
for(i=192;i<=327;i++)//第一个数最小192,最大327。其实不知道的情况下简单来说是从123-329的但是算出来是最值就稍微改了下下
{
memset(a,0,sizeof(a));v=0;//清零
a[i%10]=a[i/10%10]=a[i/100]=a[i*2%10]=a[i*2/10%10]=a[i*2/100]=a[i*3%10]=a[i*3/10%10]=a[i*3/100]=1;//统计数字
for(j=1;j<=9;j++) v+=a[j];//v表示1-9这些数字是否全部齐了
if(v==9) printf("%d %d %d\n",i,i*2,i*3);//如果齐了就输出
}
return 0;
}
来源于 https://www.luogu.org/problemnew/solution/P1008.
作者 Kelin
大部分一样,只是用数组的下标来储存原本数组的内容,再全部赋成1,如果下标重复,那么必定有数组未被赋值,则可以通过累加是否为9或循环判断a[i]是否为1
再用个flag,如第一个代码,但累加总感觉不是很严格。。。
不过这两种方法真的让人豁然开朗,比我的笨方法好不少,嗯,慢慢学吧,到最后总会越来越好的。CSDN一答结束,搞定。。。。。。
如果有人发现了什么错误,欢迎评论。