【算法打卡day35(2026-03-31 周二)】DFS专项训练2(今日算法:DFS & 记忆化搜索 & 回溯)

- 第 198 篇 -
Date: 2026 - 03- 31 | 周二
Author: 郑龙浩(仟墨)
今日算法:DFS & 记忆化搜索 & 回溯

2026-03-31-算法打卡day35-DFS专项训练2

文章目录

7-洛谷P15435-免费披萨-蓝桥杯2025国赛Python大学B组

DFS

【题目】

蓝桥小镇披萨店的老板刚刚烤制了他人生中的第 n 个披萨!为了庆祝这一重要时刻,他推出了一项名为"幸运订单"的活动,顾客有机会赢取免费披萨。以下是活动的具体规则:

  1. 生成订单编号:每位顾客需要生成一个九位数的订单编号。生成方法如下:首先,将数字 1 到 8 进行任意排列(每个数字正好出现一次),组成一个八位数。然后,在这个八位数的任意位置(可以是开头、结尾或中间)插入一个 1 到 8 的数字,从而得到一个九位数的订单编号。
  2. 计算最大公约数,赢取免费披萨:披萨店老板会计算每位顾客生成的订单编号与 n 的最大公约数(GCD)。如果某个订单编号与 n 的最大公约数最大,那么该顾客就有机会赢得免费披萨。注意:订单编号必须严格满足上述生成规则,如果有多个订单编号与 n 的最大公约数相同且达到最大值,则只有生成数值最小的订单编号的顾客能够获奖。

现在,小蓝也想参加这个活动,并希望赢取免费披萨。请你帮助小蓝找出能够让他赢得免费披萨的订单编号。

输入格式

输入一行包含一个八位的正整数 n,表示披萨店老板烤制的第 n 个披萨。

输出格式

输出一行包含一个九位的正整数表示答案,即小蓝能够赢得免费披萨的最小订单编号。

输入输出样例

12345678

输出

415637826

说明/提示

评测用例规模与约定

对于所有评测用例,107≤n<108。

【思路】

整理题目含义:

输入一个n,找到一个数字n2。n2的条件:与n有着相同因数(保证这个「因数」最大) && 且数字在1e8到1e9-1之间(数字由1-8组成,且7个数字只出现一次,只有1个数字是2次)

思路:

1 输入n,从n自身开始,从大到小遍历所有的因数,假设因数为yinshu

2 利用这个因数,反向找到对应想要的数字

  • 先找出第一个>=1e8且能被yinshu整除的数字,记为start。start就是可能满足条件的第一个8位数
    • 实现方法:从1e8开始到1e9-1循环,直到找到第一个能被yinshu整除的数字
    • 如果找不到start,就表示当前因数yinshu,说明当前 yinshu 没有对应的 9 位数倍数
  • 从start开始,每次增加yinshu,得到可能的结果curNum
    • 如果curNum在1e8~1e9-1范围内,就检查是否符合合法订单编号(全都是1-8组成,且每个数字出现了1次,只有一个数字出现了2次)
  • 如果出现了这个数字,直接输出即可(满足数字范围 && 满足订单格式)

下面代码只有90分,有2个案例超时了,其他的还好

【代码】

cpp 复制代码
/* 2026-03-31-算法打卡day35-DFS专项训练2
 * 7-洛谷P15435-免费披萨-暴力枚举-蓝桥杯2025国赛Python大学B组
 * Author:郑龙浩
 * Date:2026-03-31
 * 算法:
 */

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
// 检查num是否是合法订单编号
bool IS(ll num) {
    int numCnt[9] = {0};
    // string = to_string(num);
    while (num) {
        if (num % 10 == 9 || num % 10 == 0) return false;
        numCnt[num % 10]++; // 求出数字数量
        num /= 10;
    }
    int oneCnt = 0; // 数字数量为1
    int twoCnt = 0; // 为2
    for (int i = 1; i <= 8; i++) {
        if (numCnt[i] == 1) oneCnt++;
        else if (numCnt[i] == 2) twoCnt++;
        else {
            return false; // 如果有1个不是数量为1或2,直接return false
        }
    }
    if (oneCnt == 7 && twoCnt == 1) return true;
    else return false;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    ll N; cin >> N;
    ll n = N;
    ll yinshu;
    // 枚举所有可能的因子
    for (int i = n; i >= 1; i--) {
        if (n % i == 0) { // 找到了因数
            yinshu = i;
            // 找到[1e8, 1e9-1]之间的可以被yinshu整除的数字(yinshu对应的倍数)
            ll start;
            for (start = 1e8; start < 1e9; start++) {
                if (start % yinshu == 0) // 找到对应的第一个yinshu的倍数了
                    break;
            }         
            // 步长是yinshu,这样可以保证curNum都是因数
            for (ll curNum = start; curNum < 1e9; curNum += yinshu) { // 这样就可以保证都是yinshu的倍数了,也就是所有的curNum和n处理起来,都是相同的最大公因数,都是yinshu
                if (IS(curNum) == true) { // 如果该数既是yinshu的倍数 && 也是合法订单编号
                    cout << curNum;
                    return 0;
                }
            }
        }
    }
    return 0;
}

8-洛谷P6183-The_Rock_Game_S-DFS

这个我不会,先跳过了

【题目】

题目描述

在奶牛回家休息和娱乐之前,Farmer John 希望它们通过玩游戏获得一些智力上的刺激。

游戏板由 n n n 个相同的洞组成,这些洞最初都是空的 。一头母牛要么用石头盖住一个空的洞,要么揭开一个先前被盖住的洞。游戏状态的定义是所有洞是否被石头覆盖的情况。

游戏的目标是让奶牛到达每个可能的游戏状态一次,最后回到初始状态。

以下是他们其中一次游戏的示例(空的洞用 O 表示,用石头盖住的洞用 X 表示):

时刻 洞 1 洞 2 洞 3 描述
0 0 0 O O O 一开始所有的洞都是空的
1 1 1 O O X 盖上洞 3
2 2 2 X O X 盖上洞 1
3 3 3 X O O 打开洞 3
4 4 4 X X O 盖上洞 2
5 5 5 O X O 打开洞 1
6 6 6 O X X 盖上洞 3
7 7 7 X X X 盖上洞 1

现在牛被卡住玩不下去了!他们必须打开一个洞,然而不管他们打开哪个洞,他们都会到达一个他们已经到达过的状态。例如,如果他们从第二个洞中取出岩石,他们将到达他们在时刻 2 2 2 已经访问过的状态(X O X)。

下面是一个 3 个孔的有效解决方案:

时间 洞 1 洞 2 洞 3 描述
0 0 0 O O O 一开始所有的洞都是空的
1 1 1 O X O 盖上洞 2
2 2 2 O X X 盖上洞 3
3 3 3 O O X 打开洞 2
4 4 4 X O X 盖上洞 1
5 5 5 X X X 盖上洞 2
6 6 6 X X O 打开洞 3
7 7 7 X O O 打开洞 2
8 8 8 O O O 打开洞 1,恢复到原来的状态

现在,奶牛们厌倦了这个游戏,它们想找你帮忙。

给定 n n n,求游戏的有效解决方案序列。如果有多个解决方案,则输出任意一个

输入格式

仅一行,一个整数 n n n。

输出格式

共 2 n + 1 2^n+1 2n+1 行,每行一个长度为 n n n 的字符串,其中只包含字符 OX,该行中的第 i i i 个字符表示第 i i i 个孔在此状态下是被覆盖还是未覆盖,第一行和最后一行必须全部都是 O

输入输出样例 #1
输入 #1
复制代码
3
输出 #1
复制代码
OOO
OXO
OXX
OOX
XOX
XXX
XXO
XOO
OOO
说明/提示

对于 100 % 100\% 100% 的数据,有 1 ≤ n ≤ 15 1\le n\le15 1≤n≤15。

【思路】

【代码】

cpp 复制代码

9-洛谷P13886-分糖果-DFS-蓝桥杯2023省PythonA

DFS搜索

难点在判断条件上以及两个for

【题目】

题目描述

两种糖果分别有 9 9 9 个和 16 16 16 个,要全部分给 7 7 7 个小朋友,每个小朋友得到的糖果总数最少为 2 2 2 个最多为 5 5 5 个,问有多少种不同的分法。糖果必须全部分完。

只要有其中一个小朋友在两种方案中分到的糖果不完全相同,这两种方案就算作不同的方案。

输入格式

输出格式

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只输出这个整数,填写多余的内容将无法得分。

【思路】

整理题目:

有7个小朋友,也就意味着要给7个位置分配糖果

那么递归的深度就是7

dfs return 条件:

如果到了第7层 && a == 0 && b == 0,也就是糖果也分完了,直接总方案数ans++且return

如果到了第7层,糖果没有分完的话,方案数不++,因为当前的分配方案是不合适,直接return去尝试其他的结果好了

递归函数DFS中

递归当中可以写两个for 循环,第一层for 分配糖果a(可以分配05个),第二层分配糖果b(可以分配05个)

因为糖果每次最少分2个,最多分5个

此时就要判断,a糖果+ b糖果是否在 2到5这个区间内,只有在这个区间内的,才可以dfs递归,去尝试下一次的分配

【代码】

cpp 复制代码
/* 2026-03-31-算法打卡day35-DFS专项训练2
 * 9-洛谷P13886-分糖果-DFS-蓝桥杯2023省PythonA
 * Author:郑龙浩
 * Date:2026-03-31
 * 算法:DFS
 */

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a = 9, b = 16;
ll ans;
// pos: 当前分配了pos个位置 或 已经分配到了第pos个位置(pos位置已经分配了)
void dfs(int pos) {
    if (pos == 7) { // 当已经分配了7个位置时
        if (a == 0 && b == 0) ans++; // 如果糖果全部用过,就说明有了一个方案,直接ans ++
        return; // 如果发糖果没有用光,也要return,返回回溯去找下一个结果
    }
    for (int i = 0; i <= 5; i++) {
        if (a - i < 0) break;
        a -= i; // a糖果分配了i个
        for (int j = 0; j <= 5; j++) {
            if (b - j < 0) break;
            int total = i + j; // 当前分配糖果的数量
            if (total < 2) continue; // 如果给该同学分配的糖果数量 < 2,则表示不符合分配条件,那么就不能分,直接continue,去寻找下一个符合的分配方案去
            if (total > 5) break; // 如果给该同学分配的糖果数量大于5,那么也就没有继续分的必要了,后面的所有情况肯定都不符合
            // 不能分配的情况提前处理, 如果能分配就会走到这一步,直接分配就好了
            
            b -= j; // b糖果分配了j个
            // 分配了一次,就+1一次
            dfs(pos + 1);
            b += j; // 回溯
        }
        a += i; // 回溯
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    dfs(0); // 刚开始一个也没分配呢,也就是分配了0次
    cout << ans;
    return 0;
}

10-洛谷P2404-自然数的拆分问题

DFS & 回溯

【题目】

题目描述

任何一个大于 1 1 1 的自然数 n n n,总可以拆分成若干个小于 n n n 的自然数之和。现在给你一个自然数 n n n,要求你求出 n n n 的拆分成一些数字的和。每个拆分后的序列中的数字从小到大排序。然后你需要输出这些序列,其中字典序小的序列需要优先输出。

输入格式

输入:待拆分的自然数 n n n。

输出格式

输出:若干数的加法式子。

输入输出样例 #1

输入 #1

复制代码
7

输出 #1

复制代码
1+1+1+1+1+1+1
1+1+1+1+1+2
1+1+1+1+3
1+1+1+2+2
1+1+1+4
1+1+2+3
1+1+5
1+2+2+2
1+2+4
1+3+3
1+6
2+2+3
2+5
3+4
说明/提示

数据保证, 2 ≤ n ≤ 8 2\leq n\le 8 2≤n≤8。

【思路】

模板题,套模板罢了

注意:

dfs的开始数字是1,且下一个数字的选择范围正确,以及确定找到一个方案的时候的数量是2即可

【代码】

cpp 复制代码
/* 2026-03-31-算法打卡day35-DFS专项训练2
 * 10-洛谷P2404-自然数的拆分问题
 * Author:郑龙浩
 * Date:2026-03-31
 * 算法:DFS
 */

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int N;
vector <vector <int>> results;
vector <int> path;
int sum = 0; // 和
// curNum表示当前需要处理的数字 (当前可以选择的最小数字(保证拆分序列非降序,避免重复))
void dfs(int curNum) {
    if (sum == N && path.size() >= 2) { // 终止条件:当前和等于N 且 至少有两个数(题目要求拆分成至少两个自然数)
        results.push_back(path);  // 保存当前方案
        return;
    }
     // 剩余需要凑的和
    int remaining = N - sum; // 还有remaining剩余数字没有加入sum,所以后面可以尝试从curNum 到 remaining加入到sum中去
    // 遍历所有可能的下一个数字
    // 从curNum到remaining:保证数字不降序,且不超过剩余和
    for (int nextNum = curNum; nextNum <= remaining; nextNum++) { // 可以有多个相同的数字相加,所以nextNum下一次加入的数字也可以是上一次加入的数字curNum
        path.push_back(nextNum); // 选择当前数字
        sum += nextNum; // 更新当前和
        dfs(nextNum); // 递归处理,传入nextNum保证非降序
        path.pop_back(); // 回溯,撤掉选择,尝试下一个选择(撤掉刚才的节点(下面的),然后网上走一步,再向下一个节点前进)
        sum -= nextNum;
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> N;
    dfs(1);
    for (auto i : results) {
        int len = i.size();
        for (int j = 0; j < len - 1; j++) cout << i[j] << '+';
        cout << i[len - 1] << '\n'; // 最后一个是换行,不是+
    }
    return 0;
}

11-洛谷P2386-放苹果-DFS回溯

DFS & 回溯

【题目】

题目描述

把 m m m 个同样的苹果放在 n n n 个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法。( 5 , 1 , 1 5,1,1 5,1,1 和 1 , 1 , 5 1,1,5 1,1,5 是同一种方法)

输入格式

第一行是测试数据的数目 t t t,以下每行均包括二个整数 m m m 和 n n n,以空格分开。

输出格式

对输入的每组数据 m m m 和 n n n,用一行输出相应的结果。

输入输出样例 #1
输入 #1
复制代码
1
7 3
输出 #1
复制代码
8
输入输出样例 #2
输入 #2
复制代码
3
3 2
4 3
2 7
输出 #2
复制代码
2
4
2
说明/提示

对于所有数据,保证: 1 ≤ m , n ≤ 10 1\leq m,n\leq 10 1≤m,n≤10, 0 ≤ t ≤ 20 0 \leq t \leq 20 0≤t≤20。

【思路】

模板题上稍加修改

【代码】

cpp 复制代码
/* 2026-03-31-算法打卡day35-DFS专项训练2
 * 11-洛谷P2386-放苹果-DFS回溯
 * Author:郑龙浩
 * Date:2026-03-31
 * 算法:DFS & 回溯
 * n个盘子,每个盘子可放入0~m个苹果
 */

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int cnt = 0;
int n, m;
// 注意求的是 组合数,不是排列数,所以为了保证所有的方案都是不重复的,
// 我求方案数的时候保证其每个盘子苹果数量,是递增的即可,也就是不可能出现123,又出现了321这种情况的分配,保证递增的顺序就保证了盘子分配苹果的方案是求的组合数,而不是排列数的方案了
// pos:分配到了第pos个盘子
// lastNum // 上一个盘子放的苹果数量 // 刚开始我没有写第二个参数,导致了我的方案数出现了好多排列,比如111出现了三次,或者123,321,132,312等都出现了,但实际上这个是一种情况
// 写了这个参数后,111只会出现一次,或者122也只会出现一次,或者123也只会出现一次...
void dfs(int pos, int lastNum) {
    // pos == n + 1为终止条件
    if (pos > n) { // 如果处理到了第n + 1个盘子,就表示前面n个盘子都装过了,也就是有了一套方案了
        if (m == 0) cnt++; // 如果苹果用完了,择表示当前这个方案是可以的,直接计入总方案数即可
        return; // 如果m个苹果没有用完,择表示虽然装盘成功,有了一套方案,但是苹果并没有使用完,也不可以,返回去尝试寻找下一个方案就好了
    }
    // 剪枝是AI帮我加的,我自己不太能想到
    // 如果剩余盘子,都放如最小的苹果数量,还超过m个苹果(剩余的苹果的话)
    // 也就是,怎么放,m个苹果都不够用的,既然每个盘子放最小的苹果都不够,那么大的也是不够的,那么执行后面的代码只会浪费空间和时间,所以去掉
    int remaining = n - pos + 1; // 剩余的盘子
    if (m < remaining * lastNum) return; // 如果剩余的苹果不够分的,也就不需要分了
    // 剪枝
    for (int i = lastNum; i <= m; i++) { // 每次可以放入上一个盘子放的苹果数量 ~ m个苹果(m是剩余的苹果数量)
        // 如果放了i个苹果后,苹果是负的,择不符合常理,盘子里也不能放这些了,既然i个不能放入盘子中了,那么所有大于i的苹果的数量都不能放入盘子中了,就无需再判断了,直接break,其实相当于return了,因为break后必会执行return(隐性)
        m -= i;
        dfs(pos + 1, i);
        m += i;
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int T;
    cin >> T;
    while (T--) {
        cin >> m >> n;
        cnt = 0; // 每次计算分法之前,都要重置为0,否则方案数量cnt会继承上一组数据继续计算,会出现叠加的错误
        dfs(1, 0);
        cout << cnt << '\n';
    }
    return 0;
}

12-洛谷P6566-观星-DFS搜图

DFS 搜图

【题目】

题目描述

Jimmy 和 Symbol 约好一起看星星,浩瀚的星空可视为一个长为 N N N、宽为 M M M 的矩阵,矩阵中共有 N × M N\times M N×M 个位置,一个位置可以用坐标 ( i , j ) (i,j) (i,j)( 1 ≤ i ≤ N 1\le i\le N 1≤i≤N, 1 ≤ j ≤ M 1\le j\le M 1≤j≤M)来表示。每个位置上可能是空的,也可能有一个星星。

对于一个位置 ( i , j ) (i,j) (i,j),与其相邻的位置有左边、左上、上面、右上、右边、右下、下面、左下 8 个位置。相邻位置上的星星被视为同一个星座,这种关系有传递性,例如若 ( 1 , 1 ) , ( 1 , 2 ) , ( 1 , 3 ) (1,1),(1,2),(1,3) (1,1),(1,2),(1,3) 三个

位置上都有星星,那么这三个星星视为同一个星座。包含的星星数量相同的星座被视为一个星系(一个星系中的星座不一定相邻),星系的大小为星系中包含的所有星星数量。

由于 Symbol 太喜欢星系了,他就想考一考 Jimmy,让 Jimmy 求出星空中有多少个星系,他还想知道,最大的星系有多大。

输入格式

第一行两个整数 N , M N,M N,M 表示矩阵的长宽。

接下来 N N N 行每行 M M M 个字符,每个字符只可能是.*。这 N N N 行中第 i i i 行的第 j j j 个字符是*表示位置 ( i , j ) (i,j) (i,j) 上有一个星星,否则表示它是空的。

输出格式

仅一行两个整数,用空格分隔开,分别表示星系的数量与最大星系的大小。

输入输出样例 #1
输入 #1
复制代码
5 7
*......
..**..*
.*...*.
...*...
....*..
输出 #1
复制代码
3 4
输入输出样例 #2
输入 #2
复制代码
10 10
**..**.**.
***....*..
*...**.**.
...*..*...
..........
**...**.*.
..*.*....*
..........
***..*.*..
.***..*...
输出 #2
复制代码
4 12
说明/提示

对于 20 % 20\% 20% 的数据, N , M ≤ 20 N,M\le 20 N,M≤20,最大星系大小不超过 200。

对于 50 % 50\% 50% 的数据, N , M ≤ 400 N,M\le 400 N,M≤400。

对于 70 % 70\% 70% 的数据, N , M ≤ 1100 N,M\le 1100 N,M≤1100。

对于 100 % 100\% 100% 的数据, 2 ≤ N , M ≤ 1500 2\le N,M\le 1500 2≤N,M≤1500,最大星系大小不超过 100000。

【思路】

这是一个很明显的「搜图DFS」

分析题目:

星座:相连的星星(8个方向)

星系:星星数量相同的所有星座,不必相邻

求啥:求星系的数量 & 最大的星系是多大(星系的数量是所有星星之和)

我的思路:

dfs查找星座,给星座命名,且计算出该星座多大,将数量存入数组中
vector <int> Cnts; 从0开始命名星座,索引为名,数值为数量

map表是:key为星星明,val为星星数

遍历完所有的星座后

给Cnts数组排序,从小到大排序,为了方便计算相同数量星座的数量

创建 totalCnt,存储星系数量,初始化为1

创建Max,存储最大星系的和,初始化为0

创建curXingxiCnt = Cnts[0];存储星系的星星数量,初始化为第一个星座星星数量

如果只有1个星座,直接输出就好了,后面不用执行,记得break

遍历Cnts数组,从索引1开始遍历,如果当前的星座和前一个星座数量相同,就将当前星座数量加入curXingxiCnt

如果当前星座与前一个星座不相同的话,也就意味着当前位置是下一个星座,

  • 此时就用Max与上一个星系对比,保留最大的星系
  • 然后curXingxiCnt 重置为 当前星座数量(也就是不保留前面上一个星系的数量,重新开始计数)
  • totalCnt计数
    最后输出星系数量totalCnt & 最大Max星系数量

【代码1 】存储星座星星数量,然后计算星系数量和最大星系的星星数

cpp 复制代码
/* 2026-03-31-算法打卡day35-DFS专项训练2
 * 12-洛谷P6566-观星-DFS搜图
 * Author:郑龙浩
 * Date:2026-03-31
 * 算法:DFS遍历图
 * 方法1:存储星座,然后计算多少个星系
 */

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int N, M;
vector <int> Cnts;
int cnt;
int direction[8][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}, {1, -1}, {-1, 1}, {1, 1}, {-1, -1}};
void dfs(vector <vector<char>>& graph, vector <vector<bool>>& visited, int x, int y) {
    visited[x][y] = true;
    cnt++; 
    for (int i = 0; i < 8; i++) {
        int nextX = x + direction[i][0];
        int nextY = y + direction[i][1];
        if (nextX < 0 || nextX >= N || nextY < 0 || nextY >= M) continue;
        if (graph[nextX][nextY] == '*' && visited[nextX][nextY] == false)
            dfs(graph, visited, nextX, nextY);
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> N >> M;
    vector <vector <char>> graph(N, vector <char>(M));
    vector <vector <bool>> visited(N, vector <bool>(M));
    for (int i = 0; i < N; i++) for (int j = 0; j < M; j++) cin >> graph[i][j];
    for (int i = 0; i < N; i++) for (int j = 0; j < M; j++) {
        if (graph[i][j] == '*' && visited[i][j] == false) {
            cnt = 0;
            dfs(graph, visited, i, j);
            Cnts.push_back(cnt);
        }
    }
    int len = Cnts.size();
    if (len == 0) {
        cout << 0 << ' ' << 0;
        return 0;
    }
    if (len == 1) {
        cout << 1 << ' ' << Cnts[0];
        return 0;
    } 
    sort(Cnts.begin(), Cnts.end());
    int totalCnt = 1; // 星系数量
    int Max = Cnts[0]; // 最大星系的星星的数量
    int curXingxiCnt = Cnts[0]; // 星系中的星星数量
    
    for (int i = 1; i < len; i++) {
        if (Cnts[i] == Cnts[i - 1]) curXingxiCnt += Cnts[i];
        else if (Cnts[i] != Cnts[i - 1]) {
            Max = max(Max, curXingxiCnt);
            curXingxiCnt = Cnts[i];
            totalCnt++;
        }
    }
    // 处理最后一组
    Max = max(Max, curXingxiCnt);
    cout << totalCnt << ' ' << Max;
    return 0;
}

【代码2】直接存储每个星系的星星数量,以及星系的每个星座的星星数量

cpp 复制代码
/* 2026-03-31-算法打卡day35-DFS专项训练2
 * 12-洛谷P6566-观星-DFS搜图
 * Author:郑龙浩
 * Date:2026-04-01
 * 算法:DFS
 * 方法2:存储星系,而不是存储星座
 */

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int N, M;
vector <int> Cnts;
int cnt;
int direction[8][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}, {1, -1}, {-1, 1}, {1, 1}, {-1, -1}};
unordered_map <int, int> xingzuoXingxi; // 星座大小 -> 星系总星星数
void dfs(vector <vector<char>>& graph, vector <vector<bool>>& visited, int x, int y) {
    visited[x][y] = true;
    cnt++; 
    for (int i = 0; i < 8; i++) {
        int nextX = x + direction[i][0];
        int nextY = y + direction[i][1];
        if (nextX < 0 || nextX >= N || nextY < 0 || nextY >= M) continue;
        if (graph[nextX][nextY] == '*' && visited[nextX][nextY] == false)
            dfs(graph, visited, nextX, nextY);
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> N >> M;
    vector <vector <char>> graph(N, vector <char>(M));
    vector <vector <bool>> visited(N, vector <bool>(M));
    for (int i = 0; i < N; i++) for (int j = 0; j < M; j++) cin >> graph[i][j];
    for (int i = 0; i < N; i++) for (int j = 0; j < M; j++) {
        if (graph[i][j] == '*' && visited[i][j] == false) {
            cnt = 0;
            dfs(graph, visited, i, j);
            if (xingzuoXingxi.find(cnt) == xingzuoXingxi.end()) xingzuoXingxi[cnt] = cnt;
            else xingzuoXingxi[cnt] += cnt;
        }
    }
    int len = xingzuoXingxi.size();
    if (len == 0) {cout << "0 0"; return 0;}
    int Max = 0;
    for (auto it : xingzuoXingxi) {
        Max = max(Max, it.second);
    }
    cout << len << ' ' << Max;
    return 0;
}
相关推荐
Tanecious.6 分钟前
蓝桥杯备赛:Day3-P1102 A-B 数对
c++·蓝桥杯
汀、人工智能26 分钟前
[特殊字符] 第2课:字母异位词分组
数据结构·算法·链表·数据库架构··字母异位词分组
Tanecious.31 分钟前
蓝桥杯备赛:Day3-P1918 保龄球
c++·蓝桥杯
良木生香39 分钟前
【C++初阶】:C++类和对象(下):构造函数promax & 类型转换 & static & 友元 & 内部类 & 匿名对象 & 超级优化
c语言·开发语言·c++
小O的算法实验室1 小时前
2026年SEVC,面向主动成像卫星任务规划问题的群体智能与动态规划混合框架,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
网安INF1 小时前
数据结构第一章复习:基本概念与算法复杂度分析
数据结构·算法
幻风_huanfeng2 小时前
人工智能之数学基础:什么是凸优化问题?
人工智能·算法·机器学习·凸优化
三雷科技2 小时前
使用 `dlopen` 动态加载 `.so` 文件
开发语言·c++·算法
Yzzz-F2 小时前
Problem - 2146D1 - Codeforces &&Problem - D2 - Codeforces
算法
Kk.08022 小时前
力扣 LCR 084.全排列||
算法·leetcode·职场和发展