[NOIP1998 普及组] 三连击

文章介绍了如何通过编程解决NOIP1998竞赛中的问题,要求将1到9的数字分成三组,组成比例为1:2:3的三位数,并给出了C++代码实现,包括基础版本和升级版,涉及到计数数组、数组初始化和回溯算法的应用。
摘要由CSDN通过智能技术生成

# [NOIP1998 普及组] 三连击

## 题目背景

本题为提交答案题,您可以写程序或手算在本机上算出答案后,直接提交答案文本,也可提交答案生成程序。

## 题目描述

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

## 输入格式

## 输出格式

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

## 样例 #1

### 样例输入 #1

```

```

### 样例输出 #1

```
192 384 576
* * *
...

* * *
(剩余部分不予展示)
```

#include<iostream>  
#include<algorithm>
using namespace std;

//
//怎么使每个数字只出现一次
// 计数数组,让每个下标对应的只出现1次,check函数
//

int use[10],j,k;
void check(int num) {
	while (num) {
		use[num % 10]++;
		num /= 10;
	}
	return;
}
int main()
{
	for (int i = 101; i <= 330; i++) {//每次循环都代表一种新的情况
		j = i * 2;
		k = i * 3;
		memset(use, 0, sizeof(use));//重置数据,避免上次影响
		check(i);
		check(j);
		check(k);//计入新的
		bool can = true;
		for(int m=1;m<=9;m++){
			if(use[m]!=1){
				can = false;
				break;
			}
		}
		if (can) {
			cout << i << " " << j << " " << k << endl;
		}
	}
	return 0;
}

 升级版

# 三连击(升级版)

## 题目描述

将 $1, 2,\ldots, 9$ 共 $9$ 个数分成三组,分别组成三个三位数,且使这三个三位数的比例是 $A:B:C$,试求出所有满足条件的三个三位数,若无解,输出 `No!!!`。


//感谢黄小U饮品完善题意

## 输入格式

三个数,$A,B,C$。

## 输出格式

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

## 样例 #1

### 样例输入 #1

```
1 2 3
```

### 样例输出 #1

```
192 384 576
219 438 657
273 546 819
327 654 981
```

## 提示

保证 $A<B<C$。

---

$\text{upd 2022.8.3}$:新增加二组 Hack 数据。

#include<iostream>
using namespace std;
int a, b, c,num1,num2,num3,ans=0,use[10];
bool can;
void record(int num) {
	while (num) {
		use[num % 10] = 1;
		num /= 10;
	}
}
int main() {
	cin >> a >> b >> c;
	for (int i = 1; i <= 1000 / c; i++) {
		num1 = i * a;//这些不用初始化,因为会重新覆盖
		//类似有时候不用回溯,就是因为在下一次循环或递归的时候,是不用依据这些来判断条件的,而是通过其他参数
		//这些参数是这次要改变的,直接覆盖就行
		num2 = i * b;
		num3 = i * c;//在基础版中,循环变的每次的第一个数字
		//在升级版中,变的是这组数的因子,即i代表那个化简后的1
		can = true;
		memset(use, 0, sizeof(use));//每次循环都是新情况,需进行初始化,防止上次的影响
		record(num1), record(num2), record(num3);//记录到数组里
		for (int j = 1; j <= 9; j++) {
			if (use[j] != 1) {
				can = false;
				break;
			}
		}
		if (can) {
			ans++;
			cout << num1 << " " << num2 << " " << num3 << endl;
		}
		
		
	}
	if (ans == 0) {
		cout << "NO" << endl;//无解情况
	}
	return 0;
}
#include<iostream>
using namespace std;
int x[10] = { 0 }, a, b, c; //x[1]~x[9]为当前位置的数字 先把三个三位数合成一个9(10)位数的大数组
bool used[10] = { 0 }, ans = false;
//used数组表示该数字的使用情况 避免重复   ans判断是否有答案
int cons(int m) {   //将数组拆分成三个三位数
    int sum = 0;
    for (int i = 3 * m - 2; i <= 3 * m; i++) {
        sum *= 10;
        sum += x[i];
    }
    return sum;
}
void solve(int n) {
    if (n == 10 && cons(1) * b == cons(2) * a && cons(1) * c == cons(3) * a) {   //当n=10时x数组数字存满 开始判断
        cout << cons(1) << " " << cons(2) << " " << cons(3) << endl;//1,2,3就代表是第几个数
        ans = true;
        return;
    }//递归出口
    for (int i = 1; i <= 9; i++) {
        if (!used[i]) {//先判断,如果没用过再进行
            x[n] = i;   //存数字
            used[i] = 1;   //该数字被使用
            solve(n + 1);  //下一位继续调用
            used[i] = 0;  //恢复
            //由于判断条件涉及usd[i],所以需要回溯
            //即每次循环或递归,都会改变一些量,有些是需要回溯的,有些是不需要的
            //那些作为出口或退出,判断条件的量需要回溯,那些每次需要改变,作为每次题解,要输出的量不需要,因为下次会直接覆盖
        }
    }
    return;
}
int main() {
    cin >> a >> b >> c;
    solve(1);  //开始搜索
    if (!ans) cout << "No!!!";  //ans!=true即输出"No!!!"
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值