当前位置: 首页 > news >正文

枚举-dfs深度优先搜索

枚举-深度优先搜索

文章目录

  • 枚举-深度优先搜索
    • 前备知识
    • dfs题目一 全排列问题
      • 题目描述
      • 输入格式
      • 输出格式
      • 输入输出样例 #1
        • 输入 #1
        • 输出 #1
      • 说明/提示
      • 代码
    • dfs题目二 烤鸡
      • 题目背景
      • 题目描述
      • 输入格式
      • 输出格式
      • 输入输出样例 #1
        • 输入 #1
        • 输出 #1
      • 说明/提示
      • 代码
    • 枚举-题目1: 完全平方数分解(简单)
      • 题目描述:
      • 输入:
      • 输出:
      • 代码
    • 枚举-题目2:分苹果问题
      • 题目描述:
      • 输入:
      • 输出:
      • 代码
    • 枚举-题目3:找纸币问题
      • 题目描述:
      • 输入格式:
      • 输出格式:
      • 代码
    • 总结

前备知识

dfs和枚举的关系有点玄妙。

先说枚举 ,枚举就是把所有可能的结果全都列出来,怎么才能找到所有结果,有的很简单,比如找质数,一个函数和一个循环就可以。但是有的就不那么简单,比如写出1,2,3三个数的全排列,就要些手法。

dfs也就是深度优先搜索什么是深度优先?可以理解成一条路走到黑(走得够深),如果路被堵住了(或者找到目标),就退回到上一个路口看看有没有其他的路(回溯)。这就有点试错的意味,利用计算机快速的计算能力,穷举出答案(枚举)。

dfs有的时候就像是填字游戏。比如给你四个空,1,2,3,4填上去,有几种填法?432*1种填法,列出来就是24种(全排列)对不对?可是如果是5个数字呢(120种)6个数字呢(720种)?这个时候当然不能手工写出来,要让计算机自己打出来,如何写一个程序就是关键了。

我们要处理什么?

  • 如何说明完成现在这一步,递归的形式完成下一步?(比如我第一个数字填了1,如何表示后面的数字组合形式(比如第二个数字填2或3))
  • 如何剪枝优化,提升效率(剪枝,就是减少那些不必要的步骤,比如通常来说我回家要经过四个路口,我尝试不同路线回家的时候,有些路一眼就知道走不通,就直接放弃(也就是不是都要走够四个路口))

dfs题目一 全排列问题

题目描述

按照字典序输出自然数 111nnn 所有不重复的排列,即 nnn 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。

输入格式

一个整数 nnn

输出格式

1∼n1 \sim n1n 组成的所有不重复的数字序列,每行一个序列。

每个数字保留 555 个场宽。

输入输出样例 #1

输入 #1
3
输出 #1
1    2    31    3    22    1    32    3    13    1    23    2    1

说明/提示

1≤n≤91 \leq n \leq 91n9

代码

#include<iostream>
#include<iomanip>
using namespace std;
int arr[25] = { 0 };
bool used[21] = { 0 };
int n;
void print() {for (int i = 1; i < n; i++){cout << setw(5) << arr[i];}cout << setw(5) << arr[n] << endl;
}
void dfs(int x){//x是当前是第x格,从0开始if (x == n){print();return;}//dfs 相当于填拼图,一个位置放好之后看下一个位置,填满之后又回退到上一个步骤,看看有什么其他可能for (int i = 1; i <= n; i++) {if (used[i])continue;//如果该数字被使用过,则跳过arr[x+1] = i;//第x个位置放入拼图used[i] = true;//标记避免重复使用dfs(x + 1);//填下一个位置used[i] = false;//回退}//拿1的情况来说,刚开始填了1,1被标记为用过了,x+1格的位置填上其他的//回退到1的时候,又把1标记成未使用的,开始2开头的深度搜索return;
}
int main(){cin >> n;dfs(0);//从0位置开始,从1开始会提前结束(少了一次深入)return 0;
}

dfs题目二 烤鸡

题目背景

猪猪 Hanke 得到了一只鸡。

题目描述

猪猪 Hanke 特别喜欢吃烤鸡(本是同畜牲,相煎何太急!)Hanke 吃鸡很特别,为什么特别呢?因为他有 101010 种配料(芥末、孜然等),每种配料可以放 111333 克,任意烤鸡的美味程度为所有配料质量之和。

现在, Hanke 想要知道,如果给你一个美味程度 nnn ,请输出这 101010 种配料的所有搭配方案。

输入格式

一个正整数 nnn,表示美味程度。

输出格式

第一行,方案总数。

第二行至结束,101010 个数,表示每种配料所放的质量,按字典序排列。

如果没有符合要求的方法,就只要在第一行输出一个 000

输入输出样例 #1

输入 #1
11
输出 #1
10
1 1 1 1 1 1 1 1 1 2 
1 1 1 1 1 1 1 1 2 1 
1 1 1 1 1 1 1 2 1 1 
1 1 1 1 1 1 2 1 1 1 
1 1 1 1 1 2 1 1 1 1 
1 1 1 1 2 1 1 1 1 1 
1 1 1 2 1 1 1 1 1 1 
1 1 2 1 1 1 1 1 1 1 
1 2 1 1 1 1 1 1 1 1 
2 1 1 1 1 1 1 1 1 1

说明/提示

对于 100%100\%100% 的数据,n≤5000n \leq 5000n5000

代码

#include<iostream>
#include<vector>
using namespace std;
vector<vector<int>>solutions;//记录方案
vector<int>current(10);//记录十种结果
void dfs(int pos, int remaining)//pos表示处理的位置,remaining表示处理剩余部分
{if (pos == 10) {if (remaining == 0)solutions.push_back(current);return;//处理到最后一个也还有剩余,舍弃掉}int min_remainning = remaining - (10 - pos) * 3;//剩下的是否可以凑出来int max_remainning = remaining - (10 - pos)*1;// 剪枝//减少递归的次数,比如我来个35,直接就爆了,递归也不递归了if (min_remainning > 0 || max_remainning < 0)return;//递归for (int i = 1; i <= 3; i++) {if (remaining >= i) {current[pos] = i;dfs(pos + 1, remaining - i);}}
}
int main() {int n;cin >> n;if (n < 10 || n > 30) {cout << 0 << endl;return 0;}dfs(0, n);//current的下标从0开始//solutions可以按字典序存的原因是,一直递推到最后,自然是pos==10满足的放进去//而且是dfs()中pos放入的小的先递归结束cout << solutions.size() << endl;for (const auto& solution : solutions){for (int i = 0; i < 10; i++)cout << solution[i]<<' ';cout << endl;}return 0;
}

枚举-题目1: 完全平方数分解(简单)

题目描述:

给定一个正整数n,判断能否将n表示为两个完全平方数的和。

输入:

一个正整数n (1 ≤ n ≤ 10000)

输出:

如果能表示为两个完全平方数的和,输出"YES",否则输出"NO"

代码

#include <iostream>
#include <cmath>
using namespace std;int main() {int n;cin >> n;for (int i = 0; i * i <= n; i++) {int remaining = n - i * i;int j = sqrt(remaining);if (j * j == remaining) {cout << "YES" << endl;return 0;}}cout << "NO" << endl;return 0;
}

枚举-题目2:分苹果问题

题目描述:

有n个苹果要分给k个小朋友,每个小朋友至少分到1个苹果。问有多少种不同的分配方案?

输入:

两个正整数n和k (k ≤ n ≤ 20)

输出:

分配方案的数量

代码

#include <iostream>
using namespace std;int count_ways = 0;void enumerate(int remaining, int people, int min_val) {if (people == 1) {if (remaining >= min_val) {count_ways++;}return;}// 枚举当前人可以分到的苹果数for (int give = min_val; give <= remaining - people + 1; give++) {enumerate(remaining - give, people - 1, give);}
}int main() {int n, k;cin >> n >> k;count_ways = 0;enumerate(n, k, 1);cout << count_ways << endl;return 0;
}

枚举-题目3:找纸币问题

题目描述:

给定金额n美元,用面值为100, 20, 10, 5, 1的纸币支付,求最少需要多少张纸币。

输入格式:

一个整数n (1≤n≤10^9)

输出格式:

最少纸币数

代码

#include <iostream>
using namespace std;int main() {int n;cin >> n;int bills[] = {100, 20, 10, 5, 1};int count = 0;//从最大的纸币开始,不够一整张就看小的面额的纸币for (int i = 0; i < 5; i++) {count += n / bills[i];n %= bills[i];}cout << count << endl;return 0;
}

总结

DFS 的浪漫主义:在看似无望的深渊中,坚信必有出路;在每一次的回溯中,都带着前路的智慧重新出发。说白了,dfs就是一个试错的过程,不撞南墙不回头,人生没有回溯,每一个岔路口的选择都是未知的,但总要走下去。

ps:其他题目下一篇再分享啦,下期见

http://www.dtcms.com/a/324197.html

相关文章:

  • 女子试穿4条裤子留下血渍赔50元引争议:消费责任边界在哪?
  • C/C++类型转换(C++四大强制类型转换)
  • 北京JAVA基础面试30天打卡06
  • 编程基础之多维数组——矩阵交换行
  • 每日五个pyecharts可视化图表-line:从入门到精通 (2)
  • 周学会Matplotlib3 Python 数据可视化-绘制折线图(Lines)
  • GPT-5与中国AI发展(DeepSeek R1视角)
  • 基于Django的图书馆管理系统的设计与实现
  • drippingblues靶机通关练习笔记
  • Jotai:React轻量级状态管理新选择
  • 【Bluetooth】【Transport层篇】第六章 基于SDIO的蓝牙硬件发送协议 SDIO Transport详解
  • QT常用控件三
  • Redis 简介与 redis-plus-plus 使用指南
  • Gin 框架错误处理机制详解
  • 第三章 向量
  • 如何培养自己工程化的能力(python项目)
  • 编程基础之多维数组——同行列对角线的格
  • Qt中的设计模式:经典的MVC,MVP和MVVM
  • 娃哈哈经销商“大洗牌”:砍掉年销300万以下经销商
  • printf函数格式化输出攻略
  • 本地WSL部署接入 whisper + ollama qwen3:14b 总结字幕校对增强版
  • CodePlan:基于代码形式规划的大模型结构化推理新范式
  • 机器学习——多元线性回归
  • 【2025CVPR-图象分类方向】ProAPO:视觉分类的渐进式自动提示优化
  • 【Tomcat】企业级web应用服务器
  • 【代码随想录day 16】 力扣 112. 路径总和
  • jupyter notebook如何打开其他盘目录
  • 第二章、LSTM(Long Short-term Memory:长短时记忆网络)
  • 【CF】Day124——杂题 (鸽巢原理 | 构造 | 贪心 + 模拟)
  • Excel常用功能函数