参考文章来源: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. Map集合练习之对字符串中字母出现的次数求和

    不多说,直接上干货! 代码需求 如有这么一个字符串 String str = "fdg+avAdc bs5dDa9c-dfs"; MapTest.java package zhou ...

  2. org.apache.subversion.javahl.ClientException: Working copy is not up-to-date

    之前因为将项目中的一个文件删除了,然后添加了新的文件,svn提交的时候报错. 提示:Working copy is not up-to-date 解决办法:对应的项目上右键然后选择team,然后选择u ...

  3. 【LDAP】Openldap导入数据

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://jerry12356.blog.51cto.com/4308715/1851186 ...

  4. PHP+jQuery实现翻板抽奖(中奖概率算法)

    在电视节目中有一种抽奖形式暂且叫做翻板抽奖,台上有一个墙面,墙面放置几个大方块,主持人或者抽奖者翻开对应的方块即可揭晓中奖结果.类似的抽奖形式还可以应用在WEB中,本文将使用PHP+jQuery为您讲 ...

  5. php 自带加密、解密函数

    php 自带的加密函数  不可逆的加密函数为:md5().crypt() md5() 用来计算 MD5 哈稀.语法为:string md5(string str); crypt() 将字符串用 UNI ...

  6. Spring boot-(3) Spring Boot特性1

    本节将深入Spring Boot的细节,可以学到你想使用的或定制的Spring Boot的主要特性. 1. SpringApplication SpringApplication类为引导一个Sprin ...

  7. SQL内外连接的区别

    项目当中,需要将SQL server中的部分数据导入mongo中,由于SQL是关系型数据库的原因,需要联合多表进行查询,因此,了解了下SQL中内外连接的相关概念,以作备注: 1.内联接(典型的联接运算 ...

  8. HDU 5379——Mahjong tree——————【搜索】

    Mahjong tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Tota ...

  9. DotNetty 跨平台的网络通信库(转)

    久以来,.Net开发人员都非常羡慕Java有Netty这样,高效,稳定又易用的网络通信基础框架.终于微软的Azure团队,使用C#实现的Netty的版本发布.不但使用了C#和.Net平台的技术特点,并 ...

  10. Flex Validator的小BUG

    Flex中对同一控件如TextInput进行多种格式校验的情况下,如不注意,可能导致错误信息不显示的BUG,比如 <fx:Array id="validators"> ...