DFS回溯-经典全排列问题(力扣)

news2025/9/20 10:45:51

前言

对于全排列问题,常用的做法是设置一个vis数组来确定位置i上的数字是否被访问,因为是全排列问题,所以不同的顺序也是不一样的排列,因此每次都是从起点开始询问**(注意起点到底是0还是1)**

46全排列(最简单的模板)

class Solution {
public:
    vector<int>v;//存储一个排列
   vector<vector<int>>ans;//答案
    int vis[10];
    void dfs(vector<int> & nums){
        int n = nums.size();
       
        if(v.size() == n){
            ans.push_back(v);
            return;
        }
        for(int i = 0; i < n; i++){
            if(vis[i])continue;
            vis[i] = 1;
            v.push_back(nums[i]);
            dfs(nums);
            v.pop_back();
            vis[i] = 0;
        }
        
    }
    
    vector<vector<int>> permute(vector<int>& nums) {
        dfs(nums);
        return ans;
    }

};

解题思路

相比于全排列1,全排列2增加了重复数字,但要求不能出现重复的排列。例如原始序列1 2 1 那么全排列里 1 1 2 和 1 1 2 (两个序列的两个1位置互换了),仍然当一种排列。最好的办法就是对其进行剪枝

  if(i > 0 && nums[i] == nums[i - 1] && vis[i - 1] == 0) continue;//树层去重

借鉴卡哥的一幅图,给大家看一下
在这里插入图片描述

(类似题目)P8605 [蓝桥杯 2013 国 AC] 网络寻路

#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<stack>
#include<cstdio>
#define rep(i,a,n) for(int i = a; i <= n; i++) 
#define per(i,a,n) for(int i = n; i >= a; i--)
 
using namespace std;
 
typedef long long ll;
 
const int N = 10010;
vector<int> v[N];
int vis[N];
int n,m;
ll ans;
vector<int>st;
void dfs(int x){
	int n = v[x].size();
	if(st.size() == 3){//因为终点位置可以和起点相同,所以当路径元素为3个的时候,就开始特判 
		rep(i,0, n - 1){
			int tp = v[x][i];
			if(!vis[tp] || tp == st[0]) ans++;//没被访问或者是起点 
		}
		return ;
	}
	
	rep(i,0,n-1){
		int tp = v[x][i];
		if(!vis[tp]){
			vis[tp] = 1;
			st.push_back(tp);
			dfs(tp);
			st.pop_back();
			vis[tp] = 0;
		}
	}
}

int main(){
	cin >> n >> m;
	int u,vv;
	rep(i,1,m){
		cin >> u >> vv;
		v[u].push_back(vv);
		v[vv].push_back(u);
	}
	rep(i,1,n){
		vis[i] = 1;
		st.push_back(i);
		dfs(i);
		vis[i] = 0;
		st.pop_back();
	}
   	cout << ans;
   return 0;
 }

16全排列2

//leetcode
class Solution {
public:
    vector<int> v;
    vector<vector<int>>ans;
    int vis[10];
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        
        dfs(nums);
        return ans;
    }
    void dfs(vector<int>& nums){
        int n = nums.size();
        if(v.size() == n){
            ans.push_back(v);
            return;
        }
        for(int i = 0; i < n; i++){
            if(vis[i])continue;
            if(i > 0 && nums[i] == nums[i - 1] && vis[i - 1] == 0) continue;//树层去重
                vis[i] = 1;
                v.push_back(nums[i]);
                dfs(nums);
                v.pop_back();
                vis[i] = 0;
            
        }
    }
};

解题思路

经典的回溯问题,但分解开来看就很简单了

1 初始化:

vector<vector<string>> ans;//答案
vector<string> v(n,string(n,'.'));//二维矩阵存图,vector是一个数组,每个数组元素又是string类型,所以可以看成C语言里char类型的二维数组
  1. 按行进行DFS递归
void dfs(int u, int n,vector<string>& v){//u代表下标为u的行
        if(u == n){
            ans.push_back(v);
            return;
        }
        for(int i = 0; i < n; i++){
            if(check(u,i,n,v)){
                v[u][i] = 'Q';
                dfs(u + 1, n,v);
                v[u][i] = '.';
            }
        }
    }

3 根据题目条件判断:不能同行 同列 同斜线,同行问题不会出现,因为咱们是按照行来递归遍历的,所以只需要判断同列 同斜线问题

int check(int x, int y,int n,vector<string> &v){
        for(int i = 0; i < x; i++){
            if(v[i][y] == 'Q') return 0;
        }
        for(int i = x - 1, j = y - 1; i >= 0&&j >= 0; i--, j--){
            if(v[i][j] == 'Q') return 0;
        }
        for(int i = x - 1, j = y + 1; i >= 0 && j <= n; i--,j++){
            if(v[i][j] == 'Q') return 0;
        }
        return 1;
    }
n皇后
class Solution {
public:
    
    vector<vector<string>> ans;
    vector<vector<string>> solveNQueens(int n) {
            vector<string> v(n,string(n,'.'));
            dfs(0,n,v);
            return ans;
    }
    int check(int x, int y,int n,vector<string> &v){
        for(int i = 0; i < x; i++){
            if(v[i][y] == 'Q') return 0;
        }
        for(int i = x - 1, j = y - 1; i >= 0&&j >= 0; i--, j--){
            if(v[i][j] == 'Q') return 0;
        }
        for(int i = x - 1, j = y + 1; i >= 0 && j <= n; i--,j++){
            if(v[i][j] == 'Q') return 0;
        }
        return 1;
    }
    void dfs(int u, int n,vector<string>& v){
        if(u == n){
            ans.push_back(v);
            return;
        }
        for(int i = 0; i < n; i++){
            if(check(u,i,n,v)){
                v[u][i] = 'Q';
                dfs(u + 1, n,v);
                v[u][i] = '.';
            }
        }
    }
};

22.括号生成

class Solution {
public:
    vector<string>ans;
    //dfs搜索规则
    // 先放左括号,左括号数量lc < n, 则放
    // 然后如果左括号数量大于右括号数量且右括号数量rc < n,则放右括号
    void dfs(int lc, int rc, int n, string s){
        if(lc == n && rc == n){
            ans.push_back(s);
            return;
        }
        if(lc < n) dfs(lc + 1, rc, n, s + '(');
        if(lc > rc && rc < n) dfs(lc, rc + 1, n , s + ')');
    }
    vector<string> generateParenthesis(int n) {
            dfs(0,0,n,"");
            return ans;
    }
};

79. 单词搜索

class Solution {
    //主要思想:id标记下一个待寻找的字母,不是的话直接不寻找,vis作为标记走过的路径,不能回头走(例三)
public:
    int vis[10][10];//标记使用过的位置
    bool flag = false;
    int dx[4] = {0,0,1,-1};
    int dy[4] = {1,-1,0,0};
    void dfs(string & s,vector<vector<char>>& g,int u, int v,int id){
        if(flag) return;
        if(id == s.size()){
            flag = true;
            return;
        }
        for(int i = 0; i < 4; i++){
            int x = u + dx[i];
            int y = v + dy[i];//v写成u了,卡了一阵
            
            if(x >= 0 && x < g.size() && y>= 0 && y < g[0].size() && g[x][y] == s[id]){
                if(vis[x][y] == 1)continue;
                vis[x][y] = 1;
                dfs(s,g,x,y,id + 1);
                vis[x][y] = 0;
            }
        }
    }
    bool exist(vector<vector<char>>& board, string word) {
        for(int i = 0; i < board.size(); i++)
            for(int j = 0; j < board[0].size(); j++){
                if(board[i][j] == word[0]){
                    vis[i][j] = 1;
                    dfs(word,board,i,j,1);
                    vis[i][j] = 0;
                }
            }
            return flag;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1503924.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

训练验证码之ddddocr一个图文视频教学

目录 一、推荐文章视频一、ddddocr环境配置二、字符集验证码训练三、ocr_api_server服务搭建 一、推荐文章视频 文章原文来自这里&#xff1a;训练验证码-4、ddddocr训练字符验证码 &#xff0c; 原文文章末尾有视频介绍更多内容见训练验证码合集 一、ddddocr环境配置 1.打开…

【C++专栏】C++入门 | 函数重载、引用、内联函数

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;C专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ C入门 | 函数重载、引用、内联函数 文章编号&#xff1a;C入门 / 02 文…

Java:继承

文章目录 每日一言什么是继承&#xff1f;子类怎么访问父类的成员变量&#xff1f;不同名的怎么访问&#xff1f;同名的怎么访问&#xff1f; 子类怎么访问父类的成员方法&#xff1f;不同名的怎么访问&#xff1f;同名的怎么访问&#xff1f; 如果我就是想访问同名的父类的成员…

每日一题leetcode第2834:找出美丽数组的最小和

目录 一.题目描述 二.思路及优化 三.C代码 一.题目描述 二.思路及优化 首先我们看到这个题&#xff0c;就是根据给出的数组元素个数N&#xff0c;从[1&#xff0c;N]找出N个元素&#xff0c;使得N个元素的和最小&#xff0c;其中随便抽两个数出来&#xff0c;两个数之和不能为…

《2024国家自然科学基金青年基金》 相关申请注意事项解读

一 年龄计算 2004 对应 89 2005 对应 90 2006 对应 91 2007 对应 92 2008 对应 93 2009 对应 94 2010 对应 95 .。。 二 资助比例&#xff08;2023&#xff09; 2024年 23.13% 2023年 24% 三 2024年政策变动&#xff0c;只能申请3年的30万&#xff0c;不能像23年一样选择10-20的…

UE5.1_使用技巧(常更)

UE5.1_使用技巧&#xff08;常更&#xff09; 1. 清除所有断点 运行时忘记蓝图中的断点可能会出现运行错误的可能&#xff0c;务必运行是排除一切断点&#xff0c;逐个排查也是办法&#xff0c;但是在事件函数多的情况下会很复杂且慢节奏&#xff0c;学会一次性清除所有很有必…

【Python+Selenium学习系列5】Selenium特殊元素定位之-鼠标悬停操作

前言 Selenium模拟用户在浏览器中的操作&#xff0c;比如点击按钮。在某些场景下&#xff0c;我们需要模拟鼠标悬停的操作&#xff0c;来触发一些隐藏的元素。本文将介绍Python Selenium实现鼠标悬停操作。 鼠标悬停&#xff0c;即当光标与其名称表示的元素重叠时触发的事件&…

【js刷题:数据结构数组篇之二分查找】

二分查找 一、什么是二分查找法二、具体实现步骤1.确定确定target所在数组的**左右边界**左闭右闭左闭右开 2.取中间值左闭右闭左闭右开 3.中间元素目标值4.中间元素大于目标值5.中间元素小于目标值6.重复 三、使用条件四、js版本示例1.左闭右闭2.左闭右开 五、力扣刷题1.搜索插…

魔众智能AI系统v2.1.0版本支持主流大模型(讯飞星火、文心一言、通义千问、腾讯混元、Azure、MiniMax、Gemini)

支持主流大模型&#xff08;讯飞星火、文心一言、通义千问、腾讯混元、Azure、MiniMax、Gemini&#xff09; [新功能] 系统全局消息提示 UI 全新优化 [新功能] JS 库增加【ijs】类型字符串&#xff0c;支持默认可执行代码 [新功能] 分类快捷操作工具类 CategoryUtil [新功能…

手写简易操作系统(三)--加载Loader

前情提要 上一节我们讲了如何启动计算机&#xff0c;这一节我们讲如何加载内核&#xff0c;内核是存在于硬盘上的一段程序&#xff0c;要加载这段程序&#xff0c;那么必然需要从硬盘上读取数据&#xff0c;这里我们就需要使用 ATA PIO 模式 根据ATA规范&#xff0c;所有符合A…

基于java+springboot+vue实现的学生信息管理系统(文末源码+Lw+ppt)23-54

摘 要 人类现已进入21世纪&#xff0c;科技日新月异&#xff0c;经济、信息等方面都取得了长足的进步&#xff0c;特别是信息网络技术的飞速发展&#xff0c;对政治、经济、军事、文化等方面都产生了很大的影响。 利用计算机网络的便利&#xff0c;开发一套基于java的大学生…

「蓝桥·算法双周赛」第七场分级赛——小白入门赛

题目列表 说明 好久没打蓝桥杯的比赛&#xff0c;回来试试水&#xff0c;就开了第1、2、3一共三个题&#xff0c;第4题可惜了。1.thanks,mom【算法赛】 思路&#xff1a; 没什么好说的&#xff0c;但是当时比赛刚开始服务器有问题&#xff0c;基本提交的全WA了。#include <…

Learn OpenGL 04 纹理

纹理环绕方式 纹理坐标的范围通常是从(0, 0)到(1, 1)&#xff0c;那如果我们把纹理坐标设置在范围之外会发生什么&#xff1f;OpenGL默认的行为是重复这个纹理图像&#xff08;我们基本上忽略浮点纹理坐标的整数部分&#xff09;&#xff0c;但OpenGL提供了更多的选择&#xf…

java中的字符串比较(题目作示例)

错误的代码 import java.util.Scanner; public class one {public static void main(String[] args) {Scanner scnew Scanner(System.in);String b"47568";int i0;for ( i 0; i <3; i){String asc.next();if(ab){System.out.println("密码正确&#xff0c;登…

鸿蒙开发(二)-项目结构

鸿蒙开发(二)-项目结构 上篇文章我们讲了如何配置鸿蒙开发的基础环境&#xff0c;以及创建了第一个鸿蒙程序。 这篇我们讲述了鸿蒙应用的项目目录结构。 如图所示&#xff1a;我们切换项目project可以看到。 另一种则是Ohos模式: AppScope->app.json5 应用的全局配置 {&q…

300分钟吃透分布式缓存-23讲:Redis是如何淘汰key的?

淘汰原理 首先我们来学习 Redis 的淘汰原理。 系统线上运行中&#xff0c;内存总是昂贵且有限的&#xff0c;在数据总量远大于 Redis 可用的内存总量时&#xff0c;为了最大限度的提升访问性能&#xff0c;Redis 中只能存放最新最热的有效数据。 当 key 过期后&#xff0c;或…

【vue.js】文档解读【day 2】 | 响应式基础

如果阅读有疑问的话&#xff0c;欢迎评论或私信&#xff01;&#xff01; 本人会很热心的阐述自己的想法&#xff01;谢谢&#xff01;&#xff01;&#xff01; 文章目录 响应式基础声明响应式状态(属性)响应式代理 vs 原始值声明方法深层响应性DOM 更新时机有状态方法 响应式…

html--彩虹爱心

文章目录 js内容cssreset.min.cssstyle.css html内容 js内容 const colors ["#e03776","#8f3e98","#4687bf","#3bab6f","#f9c25e","#f47274"]; const SVG_NS http://www.w3.org/2000/svg; const SVG_XLINK &q…

VUE3 使用axios网络请求

1.新建工程 参考&#xff0c;VUE3 环境搭建&#xff1a;https://blog.csdn.net/LQ_001/article/details/136293795&#xff0c;运行命令 vue create vue-demo 2.引入axios 不管何种引用&#xff0c;都要在工程中安装 axios 包。安装命令&#xff1a;npm install --save axio…

基于springboot实现数据资产管理系统 项目【项目源码+论文说明】

基于springboot实现数据资产管理系统演示 摘要 固定资产管理系统主要是完成对系统用户管理、资产信息管理、资产变更管理、资产用途管理、资产类别管理和资产增减管理。因为利用本系统管理员可以直接录入信息&#xff0c;修改信息&#xff0c;删除信息&#xff0c;并且若在录入…