回溯,BFS,DFS学习

  首先,我承认我白活了很久,现在打代码让我很有压力,这一切都是自找的。

  这两天看了几个题目都是关于回溯和搜索,于是乎我觉得要好好搞懂一些东西。

  回溯,首先看下八皇后问题:该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。正确结果是92.

  我理解的回溯就是要从一个状态不断的去开发新的状态并判断,这个状态是最终的状态还是可以继续还是终止的状态,根据不同结果选择不同步骤。若新状态不能继续,则返回到它的上一级状态,开发其他新的状态。

 所以,关键的问题是如何开发新的状态并进行判断。我拿八皇后问题做例子:从第0行0列开始放棋子,下面是第1行0列,但是不能放,因为规则规定,所以放第1行1列,也不能,第1行2列,可以。(在每一行,能放下棋子后,则进入下一行放置棋子)。继续,第2行不能放置了,则返回上一层状态(到第1行继续放,放第1行3列).....如此继续。最终找到能放置的结果,即当 行号>=8 时(已经放满了8行)。

代码如下:

 

#include<stdio.h>

int C[50], tot = 0, n = 8, nc = 0;

 

void search(int cur) {

  int i, j;

  nc++;

  if(cur == n) {

    tot++;

  } else for(i = 0; i < n; i++) {

    int ok = 1;

    C[cur] = i;

    for(j = 0; j < cur; j++)

      if(C[cur] == C[j] || cur-C[cur] == j-C[j] || cur+C[cur] == j+C[j]) {

        ok = 0;

        break;

      }

    if(ok) search(cur+1);

  }

}

 

int main() {

  search(0);

  printf("%d/n", tot);

  printf("%d/n", nc);

  return 0;

}

 

 

 

 

#include<stdio.h>

int C[50], vis[3][50], tot = 0, n = 8, nc = 0;

 

void search(int cur) {

  int i, j;

  nc++;

  if(cur == n) {

    tot++;

  } else for(i = 0; i < n; i++) {

    if(!vis[0][i] && !vis[1][cur+i] && !vis[2][cur-i+n]) {

      C[cur] = i;

      vis[0][i] = vis[1][cur+i] = vis[2][cur-i+n] = 1;

      search(cur+1);

      vis[0][i] = vis[1][cur+i] = vis[2][cur-i+n] = 0;

    }

  }

}

 

int main() {

  memset(vis, 0, sizeof(vis));

  search(0);

  printf("%d/n", tot);

  printf("%d/n", nc);

  return 0;

}

 

 

如何记录放置的位置,除了C[]数组外,我觉得也可以用栈。

注意:

!!!!在解答树的角度来讲,回溯法正是按照深度有限的顺序在遍历解答树。!!!!

!!!!如果在回溯中使用了辅助的全局变量,则一定要及时将他们恢复原状。!!!!

使用回溯的方法:(要注意标记,处理过的要有标记)

找到递归边界,就是终极状态。并如何处理。

扩展新状态,并判断。

符合,则继续递归。否则,还原辅助变量,回溯到上一状态(此状态)继续。

 

 

DFS:

其实就可以理解成为一种回溯,不断扩展新的状态。

优点是空间很节省:只有递归栈中的节点需要保存。

BFS:

宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位址,彻底地搜索整张图,直到找到结果为止。

好处:找到的第一个解一定是离根最近的解。但空间开销大(队列中节点可能很多)

 

void BFS()

{

  给出初始状态;

 front = 1, real = 2;

 while(front < real)

      {。。。。}

 

}

 

DFS,BFS是搜索算法中主要的两种。

对于BFS,判重也是重要的。

常用的三种方法:

1.把排列“变成”整数,然后只开一个一维数组。也就是说,我们设计一套排列的编码(encoding)和解码(decoding)函数。

2.hash表。把节点变成整数,但不必一一对应。只需要设计一个所谓的哈希函数h(x),然后将任意的节点x映射到某个给定的范围[0,M-1]下。M是程序员根据可用内存大小自选的。hash函数是关键。

3.使用STL中的集合

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值