DFS排列组合与连通性

news2024/12/25 0:07:43

目录

一、前言

二、DFS与排列组合

1、DFS:自写排列算法1

(1)基础模板

(2)基于(1)输出前n个数任意m个都全排列

2、DFS:自写排列算法2(这个写法更常见)

(1)从小到大打印 n 个数的全排列

(2)从小到大打印n个数中任意m个数的排列

3、DFS:自写组合算法

4、例题——迷宫(2017年省赛,lanqiaoOJ题号641)

5、例题——寒假作业(2016年省赛,lanqiaoOJ题号1388)

(1)简单做法 (超时)

(2)自写全排列

三、DFS连通性判断

1、例题——全球变暖(2018年省赛,lanqiaoOJ题号178)


一、前言

该篇博文主要讲利用Python实现排列组合与连通性判断。

二、DFS与排列组合

求排列的系统函数,例如 Python 的 permutations()。

在某些场景下,permutations() 不能用,需要手写代码实现排列。本讲给出例题。

手写排列组合代码、暴力法、二进制法。

1、DFS:自写排列算法1

(1)基础模板

让第一个数不同,得到 n 个数列

把第 1 个和后面每个数交换。

1 2 3 4 5 ...... n

2 1 3 4 5 ...... n

......

n 2 3 4 5 ...... 1

这 n 个数列,只要第一个数不同,不管后面 n-1 个数怎么排,这 n 个数列都不同。

在上面的每个数列中,去掉第一个数,对后面的 n-1 个数进行类似的排列。例如从第 2 行的 { 2 1 3 4 5 ..... n } 进入第二层。先去掉首位 2,然后对 n-1 个做排列

1 3 4 5 ...... n

3 1 4 5 ...... n

......

n 3 4 5 ...... 1

这 n-1 个数列,只要第一个数不同,不管后面 n-2 个数怎么排,这n-1个数列都不同。这是递归的第二层。(自顶向下:这就是 DFS 的思想)

def dfs(s,t):
    if s==t:        #递归结束,产生一个全排列
        print(a[0:n])
    else:
        for i in range(s,t+1):
            a[s],a[i]=a[i],a[s]   #交换
            dfs(s+1,t)            #缩小范围
            a[i],a[s]=a[s],a[i]   #恢复

a=[1,2,3,4,5,6,7,8,9]
n=3
dfs(0,n-1)      #求前n个数的全排列

上面的代码为什么这样写,自己画棵树出来看看就明白其中的逻辑了。很多时候递归代码为什么没看懂也写不出来,就是因为你不会画树也不理解树。

但上面的代码有一个致命的缺点:不能按从小到大的顺序打印排列。

(2)基于(1)输出前n个数任意m个都全排列

如前4个数任选3个。

def dfs(s,t):
    #global cnt
    if s==3:        #递归结束,产生一个全排列
        print(a[0:3])
        #cnt+=1
    else:
        for i in range(s,t+1):
            a[s],a[i]=a[i],a[s]   #交换
            dfs(s+1,t)            #缩小范围
            a[i],a[s]=a[s],a[i]   #恢复

#cnt=0
a=[1,2,3,4,5,6,7,8,9]
n=4
dfs(0,n-1)      #求前n个数的全排列,C43A33
#print(cnt)

2、DFS:自写排列算法2(这个写法更常见)

(1)从小到大打印 n 个数的全排列

例:前 3 个数的全排列

def dfs(s,t):
    if s==t:
        print(b[0:n])   #递归结束,输出一个全排列
    else:
        for i in range(t):
            if vis[i]==False:
                vis[i]=True
                b[s]=a[i]   #存排列
                dfs(s+1,t)
                vis[i]=False

a=[1,2,3,4,5,6,7,8,9]
b=[0]*10            #记录生成的一个全排列
vis=[False]*10      #记录第i个数是否用过
n=3
dfs(0,n)

(2)从小到大打印n个数中任意m个数的排列

def dfs(s,t):
    if s==3:
        print(b[0:3])   #递归结束,输出一个排列
    else:
        for i in range(t):
            if vis[i]==False:
                vis[i]=True
                b[s]=a[i]   #存排列
                dfs(s+1,t)
                vis[i]=False

a=[1,2,3,4,5,6,7,8,9]
b=[0]*10            #记录生成的一个全排列
vis=[False]*10      #记录第i个数是否用过
n=4
dfs(0,n)    #前n个数的排列

3、DFS:自写组合算法

dfs 时,选或不选第 k 个数,就实现了各种组合

例(1) :打印二进制数。以打印 000~111 为例

(如果要反过来打印,只需要交换 8、10 行)

vis=[0]*10
def dfs(k):     #深搜到第k个
    if k==3:
        for i in range(3):
            print(vis[i],end='')
            print()
    else:
        vis[k]=0    #不选第k个
        dfs(k+1)    #继续搜下一个
        vis[k]=1    #选第k个
        dfs(k+1)    #继续搜下一个
dfs(0)

例(2):打印组合。

以 3 个数  {1, 2, 3} 为例,把上面的代码与需要打印的数列结合

def dfs(k):     #深搜到第k个
    if k==3:
        for i in range(3):
            if vis[i]==1:
                print(a[i],end='')
        print()
    else:
        vis[k]=0    #不选第k个
        dfs(k+1)    #继续搜下一个
        vis[k]=1    #选第k个
        dfs(k+1)    #继续搜下一个

vis=[0]*10
a=[1,2,3,4,5,6,7,8,9,10]
dfs(0)

4、例题——迷宫(2017年省赛,lanqiaoOJ题号641)

【问题描述】

给出一个迷宫,问迷宫内的人有多少能走出来。迷宫如下:其中 L 表示向左走,R 表示向右走,U 表示向上走,D 表示向下走。

函数 dfs(i, j):

判断从坐标点 (i,j) 出发,是否能走出去。

能走出去:返回1

否则:返回0

dfs():递归,在每个点,它根据指示牌向上、下、左、右四个方向走。

dfs() 结束的条件:

1)走出了迷宫,返回1。

2)走不出迷宫,返回0。

什么情况下走不出迷宫?

兜圈子,回到了曾经走过的点。

用 vis[i][j] 记录点 (i, j) 是否曾经走过,如果走过,就是兜圈子。

def dfs(x,y):
    if x<0 or y<0 or x>=10 or y>=10:
        return 1
    if vis[x][y]==1:
        return 0
    vis[x][y]=1
    if mp[x][y]=="L":
        return dfs(x,y-1)
    if mp[x][y]=="R":
        return dfs(x,y+1)
    if mp[x][y]=="U":
        return dfs(x-1,y)
    if mp[x][y]=="D":
        return dfs(x+1,y)

mp=[[''*10] for i in range(10)]     #二维矩阵存迷宫
for i in range(10):
    mp[i]=list(input())         #读迷宫
ans=0
for i in range(10):
    for j in range(10):
        vis=[[0]*10 for _ in range(10)]   #初始化vis[][]
        if dfs(i,j)==1:
            ans+=1
print(ans)

迷宫有 n 行 n 列,做一次 dfs(),最多需要走遍所有的点,即 O(n^2) 次;

每个点都做一次 dfs(),总复杂度 O(n^4)。

能优化吗?

  • 用不着对每个点都做一次 dfs()。
  • 从一个点出发,走过一条路径,最后走出了迷宫,那么以这条路径上所有的点为起点,都能走出迷宫;
  • 若这条路径兜圈子了,那么这条路径上所有的点都不能走出迷宫。如果对路径进行记录,就能大大减少计算量。

5、例题——寒假作业(2016年省赛,lanqiaoOJ题号1388)

(1)简单做法 (超时)

用 permutations() 函数,生成所有的排列,检查是否合法

运行时间极长!

13个数的排列:13!= 6,227,020,800

可能需要数小时

(2)自写全排列

不需要生成一个完整排列。例如一个排列的前 3 个数,如果不满足 “□+□=□”,那么后面的 9 个数不管怎么排列都不对。这种提前终止搜索的技术叫 “剪枝”。

def dfs(num):
    global ans
    if num==13:
        if b[10]==b[11]*b[12]:
            ans+=1
        return
    if num==4 and b[1]+b[2]!=b[3]:
        return #剪枝
    if num==7 and b[4]-b[5]!=b[6]:
        return
    if num==10 and b[7]*b[8]!=b[9]:
        return
    for i in range(1,14):
        if not vis[i]:
            b[num]=i
            vis[i]=1
            dfs(num+1)
            vis[i]=0
ans=0
b=[0]*15
vis=[0]*15
dfs(1)
print(ans)

三、DFS连通性判断

连通性判断:图论的一个简单问题,给定一张图,图由点和连接点的边组成,要求找到图中互相连通的部分。

1、例题——全球变暖(2018年省赛,lanqiaoOJ题号178)

【题目描述】

你有一张某海域 NxN 像素的照片,"." 表示海洋、"#" 表示陆地,如下所示:

其中 "上下左右 " 四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有 2 座岛屿。由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻 (上下左右四个相邻像素中有海洋),它就会被淹没。例如上图中的海域未来会变成如下样子:

请你计算:照片中有多少岛屿会被完全淹没。照片保证第 1 行、第 1 列、第 N 行、第 N 列的像素都是海洋。

【输入描述】

第一行包含一个整数 N (1<N<1000)。以下 N 行 N 列代表一张海域照片。

【输出描述】

输出一个整数表示答案。

连通性问题,计算步骤:

  • 遍历一个连通块 (找到这个连通块中所有的'#',标记已经搜过,不用再搜);
  • 再遍历下一个连通块……;
  • 遍历完所有连通块,统计有多少个连通块。

  • 什么岛屿不会被完全淹没?若岛中有个陆地 (称为高地),它周围都是陆地,那么这个岛不会被完全淹没。
  • 用 DFS 搜出有多少个岛(连通块),检查这个岛有没有高地,统计那些没有高地的岛 (连通块) 的数量,就是答案。
  • 计算复杂度:每个像素点只用搜一次且必须至少搜一次,共 N^2 个点,DFS 的复杂度是 O(N^2),不可能更好了。

  • 从图上任意一个点 u 开始遍历,标记 u 已经搜过。
  • 递归 u 的所有符合连通条件的邻居点。
  • 递归结束,找到了与 u 连通的所有点,这是一个连通块。
  • 不与 u 连通的、其他没有访问到的点,继续用上述步骤处理,找到所有的连通块。

import sys
sys.setrecursionlimit(60000)    #设置递归深度,否则不能通过100%的测试
def dfs(x,y):
    d=[(0,1),(0,-1),(1,0),(-1,0)]
    global flag
    global vis
    global mp
    vis[x][y]=-1
    if mp[x][y+1]=='#' and mp[x][y-1]=='#' and mp[x+1][y]=='#' and mp[x-1][y]=='#':
        flag=1
    for i in range(4):
        nx=x+d[i][0]
        ny=y+d[i][1]
        if vis[nx][ny]==0 and mp[nx][ny]=='#':
            dfs(nx,ny)

n=int(input())
mp=[]
for i in range(n):
    mp.append(list(input()))
vis=[]
for i in range(n):
    vis.append([0]*n)
ans=0
for i in range(n):
    for j in range(n):
        if vis[i][j]==0 and mp[i][j]=='#':
            flag=0
            dfs(i,j)
            if flag==0:
                ans+=1
print(ans)

以上,DFS排列组合与连通性

祝好

 

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

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

相关文章

Java安装详细教程

这里写自定义目录标题Java安装详细教程1.下载Java2&#xff0c;找到jdk8进行下载3.安装jdk4.配置环境变量5.查看是否已经成功安装Java安装详细教程 换了新电脑了&#xff0c;需要安装Java&#xff0c;如果对你也有帮助就点个赞吧~~ 文章目录Java安装详细教程1.下载Java2&#…

一阶低通滤波器学习

导读&#xff1a;电压型磁链观测器由于物理概念清晰、简单易用而备受关注。然而电压型磁链观测器包含一纯积分项&#xff0c;被积项的初始相位与直流偏置都会影响积分结果。所以对传统电压型磁链观测器的改进措施有很多&#xff0c;本期文章主要介绍采用一阶低通滤波器来替换掉…

Java程序设计实验2 | Java语言基础

*本文是博主对Java各种实验的再整理与详解&#xff0c;除了代码部分和解析部分&#xff0c;一些题目还增加了拓展部分&#xff08;⭐&#xff09;。拓展部分不是实验报告中原有的内容&#xff0c;而是博主本人自己的补充&#xff0c;以方便大家额外学习、参考。 目录 一、实验…

微信小程序使用npm包、全局数据共享和分包

文章目录导航路线使用 npm 包小程序对 npm 的支持与限制Vant Weapp1. 什么是 Vant Weapp2. 安装 Vant 组件库3. 使用 Vant 组件4. 定制全局主题样式5. 定制全局主题样式API Promise化1. 基于回调函数的异步 API 的缺点2. 什么是 API Promise 化3. 实现 API Promise 化4. 调用 P…

鸣人的影分身(动态规划 | DP | 整数划分模型)[《信息学奥赛一本通》]

题目如下&#xff1a; 在火影忍者的世界里&#xff0c;令敌人捉摸不透是非常关键的。 我们的主角漩涡鸣人所拥有的一个招数——多重影分身之术——就是一个很好的例子。 影分身是由鸣人身体的查克拉能量制造的&#xff0c;使用的查克拉越多&#xff0c;制造出的影分身越强。…

6.R语言【频数、频率统计函数】一维、二维、三维

b站课程视频链接&#xff1a; https://www.bilibili.com/video/BV19x411X7C6?p1 腾讯课堂(最新&#xff0c;但是要花钱&#xff0c;我花99&#x1f622;&#x1f622;元买了&#xff0c;感觉讲的没问题&#xff0c;就是知识点结构有点乱&#xff0c;有点废话&#xff09;&…

PostgreSQL数据库FDW——Parquet S3 MultifileMergeExecutionStateBaseS3

MultifileMergeExecutionStateBaseS3和SingleFileExecutionStateS3、MultifileExecutionStateS3类不同&#xff0c;reader成员被替换为ParquetReader *类型的readers vector。新增slots_initialized布尔变量指示slots成员是否已经初始化。slots成员是Heap类&#xff0c;Heap用于…

重装系统Windows10纯净版操作步骤(微pe)

目录 前言 操作步骤 第一步&#xff1a;格式化硬盘 第二步&#xff1a;硬盘重新分区 固态硬盘分区 机械硬盘分区 完成效果展示 第三步&#xff1a;把ISO镜像文件写入固态硬盘 第四步&#xff1a;关机拔u盘 第五步&#xff1a;开机重装系统成功 前言 1.要重装系统&am…

Webpack提取页面公共资源

1. 利用html-webpack-externals-plugin 分离基础库 在做React开发时&#xff0c;经常需要引入react和react-dom基础库&#xff0c;这样在打包的时候速度就会比较慢&#xff0c;这种情况下我们可以将这些基础库忽略掉&#xff0c;将它们通过CDN的方式直接引入&#xff0c;而不打…

apache和IIS区别?内网本地服务器项目怎么让外网访问?

Apache和IIS是比较常用的搭建服务器的中间件&#xff0c;它们之间还是有一些区别差异的&#xff0c;下面就详细说说 Apache和IIS有哪些区别&#xff0c;以及如何利用快解析实现内网主机应用让外网访问。 1.安全性 首先说说apache和IIS最基本的区别。Apache运行的操作系统通常为…

Python数学建模问题总结(3)数据可视化Cookbook指南·下

概括总结&#xff1a;五、样式&#xff1a;优化图表、数据可视1.形状&#xff1a;形状的精确程度&#xff1b;2.颜色&#xff1a;区分类别、表示数量、突出特定数据、表示含义&#xff1b;3.线&#xff1a;点划线或不同的不透明度&#xff1b;4.文字排版&#xff1a;应用于图表…

IOC/DI配置管理第三方bean及注解开发。

目录 一、IOC/DI 配置管理第三方bean 1、配置第三方bean 2、加载properties 文件 3、核心容器 二、注解开发 1、注解开发定义bean 2、纯注解开发模式 3、注解开发bean作用范围与生命周期管理 4、注解开发依赖注入 三、IOC/DI注解开发管理第三方bean 1、注解开发管…

深度学习中有哪些从数学模型或相关理论出发, 且真正行之有效的文章?

自深度学习兴起后&#xff0c;深层网路对图像进行特征学习&#xff0c;将低层次的基础特征聚合成更高级的语义特征&#xff0c;取得突出的识别效果&#xff0c;在图像识别、分割及目标检测三大领域得到了众多应用。深度学习算法基本上是由多个网络层搭建&#xff0c;每个网络层…

SpringBoot自动装配

前言 Spring翻译为中文是“春天”&#xff0c;的确&#xff0c;在某段时间内&#xff0c;它给Java开发人员带来过春天&#xff0c;但是随着我们项目规模的扩大&#xff0c;Spring需要配置的地方就越来越多&#xff0c;夸张点说&#xff0c;“配置两小时&#xff0c;Coding五分…

Open3D Usage

Open3D UsageWhat is open3Dopen3D 核心功能包括&#xff1a;python quick start交互指令显示点云**read_point_cloud** ParametersReturnPointCloud的属性&#xff1a;加载ply点云&#xff1a;显示单帧点云&#xff1a;批量单帧显示点云可视化**draw_geometries** Parameters含…

Uniswap v3 详解(三):交易过程

交易过程 v3 的 UniswapV3Pool 提供了比较底层的交易接口&#xff0c;而在 SwapRouter 合约中封装了面向用户的交易接口&#xff1a; exactInput&#xff1a;指定交易对路径&#xff0c;付出的 x token 数和预期得到的最小 y token 数&#xff08;x, y 可以互换&#xff09;e…

Studio One2023新版本更新功能介绍

Studio One 6是一款非常专业的音乐创作编辑软件。为用户提供了所有一切你所需要创作的功能&#xff0c;包括所有的歌曲、项目、仪表板等动能&#xff0c;而且还自定义添加配置文件&#xff0c;良好的界面交互和丰富的功能板块&#xff0c;再结合优秀的性能&#xff0c;能够满足…

基于SpringBoot的SSMP整合(数据层)

模块创建 新建&#xff1a; 添加依赖项&#xff1a; 由于parent没有版本维护&#xff0c;还需在pom.xml文件再次添加&#xff1a; <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version…

Django REST framework--类视图

Django REST framework--类视图基于类的视图APIView类视图generics通用类视图视图集DRF框架路由基于类的视图 项目开发中要不断思考如何让代码保持高内聚&#xff0c;低耦合&#xff0c;因此优化代码的道路上一直都不停歇。目前开发的视图是基于函数形式的&#xff0c;特点是灵…

Effective Objective-C 2.0学习记录(四)

学习记录15.用前缀避免命名空间冲突16.提供“全能初始化方法”17.实现description方法debugDescription&#xff1a;18.尽量使用不可变对象19.使用清晰而协调的命名方式类与协议的命名20.为私有方法名加前缀21.理解OC错误模型22.理解NSCopying协议深拷贝和浅拷贝15.用前缀避免命…