三连击问题求解

三连击问题

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一答结束,搞定。。。。。。

如果有人发现了什么错误,欢迎评论。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值