参考文章来源:http://blog.csdn.net/pengwill97/article/details/54850852
题目在这里HDU.1342
最近在练习DFS,就找了一些题来做,力求自我总结,有所收获,这个是第一道题目。
首先,深度优先搜索(DFS,Depth-First Search )是搜索手段中的一种,总某个状态开始,不断转移状态直到状态无法转移,然后就退回到上一步的状态,继续转移到其他状态,重复以上过程,直到找到最终的解,所以看上去用递归来写会比教简单。

现在,分析这道题,给出k个(6< k < 13)升的数字,从中找出6个升序的数字,按照顺序输出全部可能,按照DFS来做,一条一条的输出。

先给出代码,如下

#include<stdio.h>
int a[20], b[10], k;
void dfs(int position, int ans)
{
if (ans == 6)
{
for (int i = 0; i < 5; i++)
printf("%d ", b[i]);
printf("%d\n", b[5]);
return;
}
if (b[0] == a[k - 5]) position = k+1;
if (position >= k) return;
b[ans] = a[position];
dfs(position + 1, ans+1);
dfs(position + 1, ans);
}
int main()
{
int flag = 0, i;
while (scanf("%d", &k) != EOF) {
if (k == 0)break;
if (flag != 0) printf("\n");
for (i = 0; i < k; i++)scanf("%d", &a[i]);
dfs(0, 0);
flag = 1;
}
return 0;
}

main函数分析如下:

int main()
{
int flag = 0, i;
while (scanf("%d", &k) != EOF) {
if (k == 0)break;
if (flag != 0) printf("\n");
for (i = 0; i < k; i++)scanf("%d", &a[i]);
dfs(0, 0);
flag = 1;
}
return 0;
}

根据题目要求,输入数据,唯一的要求是最后一组后面没空行,也就是每一组之间有个空行,所以用了个flag来控制,输入0控制退出。
接下来是dfs函数:

void dfs(int position, int ans)
{
if (ans == 6)
{
for (int i = 0; i < 5; i++)
printf("%d ", b[i]);
printf("%d\n", b[5]);
return;
}
/*if (b[0] == a[k - 5]) position = k + 1;*/
if (position >= k) return;
b[ans] = a[position];
dfs(position + 1, ans);
dfs(position + 1, ans+1);
}

首先判断是否达到条件边界,即是否满足6个升序数字,答案保存在数组b中,在这里使用传进来的形参之一的ans作为判断标准,看ans是否为6,如果为6,就代表找到了一个可行解,就可以进行一次输出了,输出之后返回上一个递归。
接下来是一个返回语句,如果position大于等于k,就直接返回,这样看来,position是代表当前要搜索的那个数字的数组下标。很显然,如果搜索超过了k,而只给了k个数,只是越界了,所以要返回。
之后,是一个赋值语句,将数组a在position位置的数字保存到数组b的ans位置上。
最后,是两个dfs函数。参数其中一个都是position+1,说明都是将数组a向前推进了一个位置,然后另外一个参数分别是ans和ans+1,即是否选择将数组b的下一个位置的数字包含进来。也就是说,在没有达到边界条件的时候,每次都可以选择将下一个数字加入数组b,或者不加入,这就是两个选择,在接下去的数字里都会决定加入或者不加入然后判断是否满足边界条件。直到输出所有解。

所以,我觉得先是这样:

……
之后,是这样:

这里以其中一个分支为例子,当ans+1等于6,说明已经找到了一个可行解,就可以进行输出了。

分支如下:


事实上,当进行到dfs(6,6)的时候,就已经输出了一次,所以没有进入dfs(7,7),返回的时候进入dfs(7,6),然后又进行了一次输出。

这里先写了dfs(position+1,ans+1),所以第一条分支就是最左边的这一条,输出之后返回上一个dfs函数,找旁边的一条分支,知道最后一条分支都走完,程序就结束了,也就得到了所有的解。
现在,回过头来,在上面的dfs函数中我注释了一条语句:

if (b[0] == a[k - 5])   position = k+1;
if (position >= k) return;

这是干嘛的呢?
本来写上面的代码提交后,AC了,时间是15MS,所以我想把的时间它降下来,就有了上面这一句。
当数组b的第一个数字和数组a的第k-5个数字相等的时候,直接将k+1的值赋值给position,实际上,当和下一句和在一起的时候,它就有了跳过某些不合题意的解的能力,也就是剪枝

图如下:


在这里,它把从dfs(2,0)之后的分支都给剪了,至于为什么剪这里?
可以看到,数组b的第一个数字和数组a的第k-5个数字的时候,这个时候依然会往下搜索,但是,即使再把之后的所有数字都放入数组b中,那也才5个数字,而题目是需要6个数字,所以在数目都凑不齐的情况下,应该没有再往下搜索的必要了吧。

最后,还有一个问题

虽然题目只是用了DFS算法,但是做这道题的时候我依然交了不少的WA,因为在这之前,我都是先写的dfs(position+1,ans),好像从逻辑上看也没有错,都是加入或者不加入的问题。
但是这样却得不到答案,好一点会得到几组都是7的输出,坏一点,在没有得到答案的情况下就直接退出了。
为什么会得到都是7的输出?
我找了一下原因,我加入前面的剪枝语句,这样一来,当第一次走到dfs(3,0)的时候数组b中包含的数字只有一个就是数组a的最后一个数字,当返回的时候,b中仍然停留这这个数字没有还原,这样就会反复执行position=k+1;
但是如果不加这一句的话,在递归过程中就结束了,程序也没有跑完,也许是栈溢出了。
无奈╮(╯▽╰)。换了个顺序,就过了。Orz

DFS练习一---HDU 1342的更多相关文章

  1. hdu 1342(DFS)

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

  2. (DFS)展开字符串 -- hdu -- 1274

    http://acm.hdu.edu.cn/showproblem.php?pid=1274 展开字符串 Time Limit: 2000/1000 MS (Java/Others)    Memor ...

  3. DFS(连通块) HDU 1241 Oil Deposits

    题目传送门 /* DFS:油田问题,一道经典的DFS求连通块.当初的难题,现在看上去不过如此啊 */ /************************************************ ...

  4. hdu 1342.. 复习广搜 顺便练习一下一个脑残的格式

    In a Lotto I have ever played, one has to select 6 numbers from the set {1,2,...,49}. A popular stra ...

  5. HDOJ(HDU).1035 Robot Motion (DFS)

    HDOJ(HDU).1035 Robot Motion [从零开始DFS(4)] 点我挑战题目 从零开始DFS HDOJ.1342 Lotto [从零开始DFS(0)] - DFS思想与框架/双重DF ...

  6. HDOJ(HDU).1016 Prime Ring Problem (DFS)

    HDOJ(HDU).1016 Prime Ring Problem (DFS) [从零开始DFS(3)] 从零开始DFS HDOJ.1342 Lotto [从零开始DFS(0)] - DFS思想与框架 ...

  7. hdoj - 1342 Lotto

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

  8. 搜索(DFS)

    不知道为什么~除了我室友其他的同学都觉得DFS很简单~且比BFS容易得多........我真心不觉得啊T T~我真心觉得BFS比DFS简单得多................= = 为了把DFS完全搞 ...

  9. HDU题解索引

    HDU 1000 A + B Problem  I/O HDU 1001 Sum Problem  数学 HDU 1002 A + B Problem II  高精度加法 HDU 1003 Maxsu ...

随机推荐

  1. jdk 动态代理 数据连接池

    package com.itheima.datasource; import java.io.PrintWriter; import java.lang.reflect.InvocationHandl ...

  2. struts2的java.lang.NoSuchMethodException异常处理

    1. 你有没有试试看 其它的方法能不能用,要是都是这种情况的话,可能是你的Action类没有继承structs里面的DispatchAction或者其它的类.还有你注意下方法的参数列表,类型顺序要正确 ...

  3. Spring boot-(3) Spring Boot特性2

    1. 外部配置 Spring Boot支持外部配置,以便可以在不同的环境中使用相同的应用程序代码.可以使用properties文件,YAML文件,环境变量或命令行参数进行外部配置.可以使用@Value ...

  4. HDU 4512——吉哥系列故事——完美队形I——————【LCIS应用】

    吉哥系列故事——完美队形I Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Tot ...

  5. MyEclipse项目中的文件点击右键Team选项中没有提交到SVN中的选项是怎么回事

    MyEclipse项目中的文件点击右键Team选项中没有提交到SVN中的选项是怎么回事 其实你已经可以百度到很多方法: 例如下面博客提供的 http://www.xuebuyuan.com/95285 ...

  6. Ubuntu15.10下安装Docker

    1.首先查看linux系统版本 head -n 1 /etc/issue 2.升级包管理器 sudo apt-get update sudo apt-get install apt-transport ...

  7. promise之nodejsQ的详细用法总结

    这里主要讲node.js中Q的各种用法及说明总结,不详细介绍promise及原理.关于promise介绍可以查看我的另一篇文章: https://www.cnblogs.com/yzeng/p/976 ...

  8. C#数字图像处理算法学习笔记(二)--点运算与直方图

    C#数字图像处理算法学习笔记(二)--点运算与直方图 在数字图像处理中,点运算是一种简单而重要的技术.点运算只是根据对象的像素的输入灰度值来决定像素的输出灰度值的图像处理运算.它有时也被称为对比度增强 ...

  9. C# 一些零零碎碎的方法,都是些帮助类,留存,也希望能帮助到各位

    ---------------------------------------------------------------------------------------------------- ...

  10. HttpClient4.3.3 禁止自动重定向

    HttpClient4.3中默认允许自动重定向,导致程序中不能跟踪跳转情况,其实只需要在RequestConfig中setRedirectsEnabled(false)即可(默认是true): pri ...