# [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;
}