参考文章来源: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. zepto.js常用操作

    zepto.js是移动端的jquery,但是并没有提供所有与jquery类似的api.Zepto设计的目的是有一个5-10k的通用库.下载并快速执行.有一个熟悉通用的API,所以你能把你主要的精力放到 ...

  2. ErlangC 最佳人力效益指标

    以平均服务时间(AHT)180秒,顾客来电量每15分钟150通以及服务目标时间在20秒内为例子说明最佳人力效益指标.此假设条件下由Erlang C模拟器的结果如下图, 假设我希望客服中心的期望服务水准 ...

  3. 祝高二学弟学妹AK NOIp2018!!!!!!

         

  4. dom父节点

  5. playbook+roles

    playbook setup ansible_all_ipv4_addresses # ipv4的所有地址 ansible_all_ipv6_addresses # ipv6的所有地址 ansible ...

  6. web worker技术-js新线程

    web worker的小例子,用来入门很合适,建议启动服务来开发.可以使用node的anywhere. <!DOCTYPE html> <html lang="en&quo ...

  7. Spring实践系列-入门篇(一)

    本文主要介绍了在本地搭建并运行一个Spring应用,演示了Spring依赖注入的特性 1 环境搭建 1.1 Maven依赖 目前只用到依赖注入的功能,故以下三个包已满足使用. <properti ...

  8. 关于form的action路径填写

    一:可以是相对路径: 1.action="<%=request.getContextPath() %>/html/index.html"  <%=request. ...

  9. Moodle-3.1.2 (Ubuntu 16.04 )

    平台: Ubuntu 类型: 虚拟机镜像 软件包: moodle-3.1.2 commercial education moodle open-source 服务优惠价: 按服务商许可协议 云服务器费 ...

  10. 更改Anaconda中Jupyter的默认文件保存目录

    转载:https://blog.csdn.net/u014552678/article/details/62046638 总结:修改Anaconda中的Jupyter Notebook默认工作路径的三 ...