参考文章来源: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. bootstrap-datetimepicker:基于twitter bootstrap的日期/时间选择控件

    bootstrap-datetimepicker是一个基于twitter bootstrap的简单日期/时间选择控件. <!DOCTYPE HTML> <html> <h ...

  2. thinkphp3.2 删除Runtime目录里的缓存文件,标记一下,以下好找。

    操作如下: utility::clearCache("Data"); 或 utility::clearCache("Data-Logs"); class uti ...

  3. HDU 5375——Gray code——————【dp||讨论】

    Gray code Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total S ...

  4. Windows窗体应用开发2--窗体和控件

    1.Windows窗体应用程序的各种组件 2.windows窗体控件的主要类别和功能 3.Windows窗体应用程序处理事件的方法 4.添加并配置Windows窗体和控件 5.创建时间处理程序并监视程 ...

  5. 初学者配置第一个spring mvc Demo

    1.web.xml的配置 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi= ...

  6. Net-SNMP(V3协议)安装配置笔记(CentOS 5.2)(转)

    原出处:http://blog.ihipop.info/2010/03/722.html 为了这颗仙人掌(cacti),我必须先部署(Net-SNMP), 同时我为了安全因素,也为了简便考虑,决定采用 ...

  7. [C#]为什么Interface里的成员不能使用static修饰?

    首先引用MSDN里的原文 Interface members are automatically public, and they can't include any access modifiers ...

  8. Android 6.0 动态权限申请

    1. 概述 Android 6.0 (API 23) 之前应用的权限在安装时全部授予,运行时应用不再需要询问用户.在 Android 6.0 或更高版本对权限进行了分类,对某些涉及到用户隐私的权限可在 ...

  9. 解决 MVC4 Code First 数据迁移 数据库发生更改导致调试失败解决方法(二)

    文章转载自:http://www.cnblogs.com/amoniyibeizi/p/4486617.html 前几天学MVC过程中,遇到更改Model类以后,运行程序就会出现数据已更改的问题导致调 ...

  10. 安装office提示Office 16 Click-to-Run Extensibility Component

    今天安装office时,提示Office 16 Click-to-Run Extensibility Component或者Office 15 Click-to-Run Extensibility C ...