Lotto [从零开始DFS(0)]

点我挑战题目

从零开始DFS

HDOJ.1342 Lotto [从零开始DFS(0)] — DFS思想与框架/双重DFS

HDOJ.1010 Tempter of the Bone [从零开始DFS(1)] —DFS四向搜索/奇偶剪枝

HDOJ(HDU).1015 Safecracker [从零开始DFS(2)] —DFS四向搜索变种

HDOJ(HDU).1016 Prime Ring Problem (DFS) [从零开始DFS(3)] —小结:做DFS题目的关注点

HDOJ(HDU).1035 Robot Motion [从零开始DFS(4)]—DFS题目练习

HDOJ(HDU).1241 Oil Deposits(DFS) [从零开始DFS(5)] —DFS八向搜索/双重for循环遍历

HDOJ(HDU).1258 Sum It Up (DFS) [从零开始DFS(6)] —DFS双重搜索/去重技巧

HDOJ(HDU).1045 Fire Net [从零开始DFS(7)]—DFS练习/check函数的思想

题意分析

给出k(6 < k < 13)个数字,要求从这k个数字中选出升序的6个数字,并且按照字典序输出全部的可能,给出的k个数字已经按照升序排列好。

乍一看以为是排列组合,怎么想也想不到是用dfs来解决。按照这个数字选或者不选的逻辑,以为是dp什么的。最后看了题解才知道用dfs的方法做,也算是长见识了。作为dfs的第一道题,好好写,纪念一下。

dfs一般采用递归写法,或许是相比于bfs更加好写吧,所以能用dfs写的都用dfs了。

既然是深度优先,思路就是沿着一条路一直走,直到走到死胡同,原路返回,返回到有多条道路的地方换其他路走。直到这条支路全部都访问过了,按照原路返回,回到起点,如果起点还有别的支路,那么继续访问,反之结束整个搜索过程。



(图1-1)

Tip:数字为访问顺序,红色代表前进的过程,蓝色代表返回的过程。这里可以看到,是永远先访问上边的节点,其次是下面的节点。

Tiip:故意画成树的样子,树也是一张图呀。

实际解题的时候不可能无所约束的搜索下去,原因之一是会超时(TLE),原因之二就是没有那个必要。那么就需要减小搜索的规模,俗称剪枝。个人的理解是,当搜索到某一步的时候,继续搜索下去的解,明显不满足题目的要求时,终止这次搜索。



(图1-2)

Tip:如图,绿色节点均为不满足题意的解,那么当我搜索到绿色箭头所指向的点的时候,就没必要继续往下搜索了,即后续的3、4、5、6、7、8步骤均为多余的。

Tiip:由此可见,当数据规模非常大的时候,剪枝可以显著提高程序运行的效率。有时候没剪枝T了,剪枝就AC了。

回到本题。对于给定数字,面临的选择就是选或者不选,是不是和上面的树逻辑上很相似。先上代码,揉碎了慢慢写。。

代码总览

/*
Title:HDOJ.1342
Author:pengwill
Date:2017-2-3
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int a[20],b[10],n;
void dfs(int num, int pos)
{
if(num == 7){
for(int i =1 ;i<num; ++i){
if(i == 1) printf("%d",b[i]);
else printf(" %d",b[i]);
}
printf("\n");return;
}
if(pos>n) return;
b[num] = a[pos];
dfs(num+1,pos+1);
dfs(num,pos+1);
}
int main()
{
int t = 0;
while(scanf("%d",&n) && n != 0){
if(t!=0) printf("\n");
for(int i = 1; i<=n; ++i) scanf("%d",&a[i]);
dfs(1,1);
t++;
}
return 0;
}

从main函数开始:

while(scanf("%d",&n) && n != 0){
if(t!=0) printf("\n");
for(int i = 1; i<=n; ++i) scanf("%d",&a[i]); t++;
}

这里是数据的读入部分,题目要求每组数据中间要有空行,所以引入变量t。

那么关键就在于dfs函数。

void dfs(int num, int pos)
{
if(num == 7){
for(int i =1 ;i<num; ++i){
if(i == 1) printf("%d",b[i]);
else printf(" %d",b[i]);
}
printf("\n");return;
}
if(pos>n) return;
b[num] = a[pos];
dfs(num+1,pos+1);
dfs(num,pos+1);
}

dfs函数有2个形参,num和pos,乍一看不知道他们的作用,先姑且放着。

之后是对于num是否为7的一个判断。如果为7的话,进行一个输出,应该就是题目要求的输出,数组b中保存着结果。可见num应该是判断是否构成了6位的排列,当num为7递归调用dfs时,用return语句终止这次搜索。原因很简单,题目只需要我找6位排列数,干嘛找7位的。

这样的判断,叫做递归边界(如有错误请各位指正)。递归边界可以是判断是否找到了解,如果找到了一组可行的解,就不进行递归了。当然要具体问题具体分析。

向下看,是对pos是否大于n的判断,如果大于n也就终止搜索了。n表示的是每组数据数字的个数,根据这个也可以想到,应该是从n个数中选6个,如果现在的位置是n+1(数据中根本没有这个数),当然不符合题意,终止。接着是一个赋值语句,应该可以想到是选中a数组pos这个位置的数字,把它写到b的num这个位置。

下面关键来了:

dfs(num+1,pos+1);
dfs(num,pos+1);

现在已经选中了a数组pos位置的数字,如果选它的话,那么就看下一位置选谁(这个位置是相对于数组b而言的),如果不选这个数字,那么对于这一位置,我们看看a数组下一个数字选还是不选。



(图1-3)

Tip:原谅我糟糕的画图技术



(图1-4)

如图所示,对于a中某一个数,有选或者不选2中选择(蓝色代表选,红色代表不选),组成了这样一颗树,直到num==7的是,结束搜索。

由此可以总结出dfs大概的函数模型

void dfs( 参数 )
{
// 递归边界
// 可以是检查是否满足解的要求 // 完成某系动作
// 继续递归调用dfs
}

这里只是皮毛啊,要想深入学习,多做题吧!

传送门:

HDOJ.1010 Tempter of the Bone [从零开始DFS(1)]

HDOJ.1342 Lotto (DFS)的更多相关文章

  1. hdoj 1342 Lotto【dfs】

    Lotto Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submi ...

  2. Lotto(dfs)

    Lotto Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 131072/65536K (Java/Other) Total Submis ...

  3. hdoj - 1342 Lotto

    Problem Description In a Lotto I have ever played, one has to select 6 numbers from the set {1,2,... ...

  4. LeetCode Subsets II (DFS)

    题意: 给一个集合,有n个可能相同的元素,求出所有的子集(包括空集,但是不能重复). 思路: 看这个就差不多了.LEETCODE SUBSETS (DFS) class Solution { publ ...

  5. LeetCode Subsets (DFS)

    题意: 给一个集合,有n个互不相同的元素,求出所有的子集(包括空集,但是不能重复). 思路: DFS方法:由于集合中的元素是不可能出现相同的,所以不用解决相同的元素而导致重复统计. class Sol ...

  6. HDU 2553 N皇后问题(dfs)

    N皇后问题 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description 在 ...

  7. 深搜(DFS)广搜(BFS)详解

    图的深搜与广搜 一.介绍: p { margin-bottom: 0.25cm; direction: ltr; line-height: 120%; text-align: justify; orp ...

  8. 【算法导论】图的深度优先搜索遍历(DFS)

    关于图的存储在上一篇文章中已经讲述,在这里不在赘述.下面我们介绍图的深度优先搜索遍历(DFS). 深度优先搜索遍历实在访问了顶点vi后,访问vi的一个邻接点vj:访问vj之后,又访问vj的一个邻接点, ...

  9. 深度优先搜索(DFS)与广度优先搜索(BFS)的Java实现

    1.基础部分 在图中实现最基本的操作之一就是搜索从一个指定顶点可以到达哪些顶点,比如从武汉出发的高铁可以到达哪些城市,一些城市可以直达,一些城市不能直达.现在有一份全国高铁模拟图,要从某个城市(顶点) ...

随机推荐

  1. JavaWeb项目生成PDF文件添加水印图片并导出

    一.前言 首先需要在Maven中添加相应的jar包依赖,若项目没用到Maven,也可自行下载相应所需的jar包(itextpdf.jar 与 itext-asian.jar),如下图所示.点此下载 M ...

  2. 微信小程序—day03

    昨日问题 接着上一篇,昨天遇到的scroll-view组件不能滚动的问题. 今天经过调试,发现是由于:图片的实际宽高,大于给image设定的宽高导致的. 解决办法: 减小图片的实际宽高,使之小于ima ...

  3. 通过批处理命令for提取数据

    前两天有这么个小需求: 在cmd中运行某测试工具后,会返回一个json结果,其中有一个参数的值每次都变且经常要用,正常情况复制粘贴就好了,但这个值非常长,配上cmd的标记+粘贴的行为,就很酸爽了.然后 ...

  4. 安装mysql-5.7.12-winx64

    之前安装mysql时未做总结,换新电脑,补上安装记录,安装的时候,找了些网友的安装记录,发现好多坑 1.mysql-5.7.12-winx64.zip下载 官方下载地址:http://dev.mysq ...

  5. jQuery用unbind方法去掉hover事件及其他方法介绍

    近日项目开发十分的繁忙,其中一个需求是实现响应式导航.(响应式的问题我们在css相关的博客中再交流) 大家都知道导航是需要下来菜单效果的,必然就会用到 jQuery的 hover() 方法.若是导航放 ...

  6. LeetCode 108——将有序数组转化为二叉搜索树

    1. 题目 2. 解答 一棵高度平衡的二叉搜索树意味着根节点的左右子树包含相同数量的节点,也就是根节点为有序数组的中值. 因此,我们将数组的中值作为根节点,然后再递归分别得到左半部分数据转化的左子树和 ...

  7. 感知机(perceptron)

  8. Python3 Tkinter-Checkbutton

    1.多选按钮创建 from tkinter import * root=Tk() Checkbutton(root,text='python').pack() root.mainloop() 2.绑定 ...

  9. 十一:Centralized Cache Management in HDFS 集中缓存管理

    集中的HDFS缓存管理,该机制可以让用户缓存特定的hdfs路径,这些块缓存在堆外内存中.namenode指导datanode完成这个工作. Centralized cache management i ...

  10. HADOOP docker(四):安装hive

    1.hive简介2.安装hive2.1 环境准备2.1.1 下载安装包2.1.2 设置hive用户的环境变量2.1.3 hive服务端配置文件2.1.4 hive客户端配置文件2.1.4 分发hive ...