[洛谷]P1008 三连击

新手必做模拟

Posted by CloudingYu on February 10, 2022

题目描述

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

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

输出格式

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

解决思路

很多大佬都是用循环模拟的,在这里我就不赘述了。我想介绍一种新的思路,就是深度优先搜索+回溯

$dfs$ 作为一种暴力的算法,在一些只提交答案的题目中很占优势(不必在意时间复杂度)。

这道题的思路就是依次搜索 $3$ 个三位数上每一位的数字,当搜索完 $9$ 个数字后,判断是否符合题意并输出就行了。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
using namespace std;
int a[10];//存储三个三位数
bool b[10];//判断数字是否使用过
void print()//判断+输出结果
{
    int b = 100 * a[1] + 10 * a[2] + a[3]; // 计算第一个三位数
    int c = 100 * a[4] + 10 * a[5] + a[6]; // 计算第二个三位数
    int d = 100 * a[7] + 10 * a[8] + a[9]; // 计算第三个三位数
    if (d == 3 * b && c == 2 * b)          // 如果b:c:d=1:2:3
    {
        for (int i = 1; i <= 7; i += 3) // 循环步长为3
            cout << a[i] << a[i + 1] << a[i + 2] << " ";
        cout << endl;
    }
    return;
}
void dfs(int k)
{
    int maxn = 9;    // 搜索1-9
    if (k == 1)      // 若是第一个数的百位数
        maxn = 3;    // 搜索1-3
    else if (k == 4) // 若事第二个数的百位数
        maxn = 6;    // 搜索1-6
    for (int i = 1; i <= maxn; i++)
    {
        if (b[i])     // 如果i被使用过
            continue; // 跳过该轮循环
        a[k] = i;
        b[i] = 1;    // 将i标记为使用过
        if (k == 9)  // 如果搜完了
            print(); // 判断+输出
        else
            dfs(k + 1); // 继续下一位数搜索
        a[k] = 0;       // 回溯
        b[i] = 0;       // 回溯
    }
    return;
}
int main()
{
    dfs(1); // 从第一个数搜起
    return 0;
}