深度优先搜索dfs

(1)定义

深度优先搜索也叫深度优先遍历,简称DFS。假设我们需要在某个房间里面寻找钥匙,无论从那一间房都可以,比如主卧。然后从房间的一个角开始,将房间内的墙角、床头柜、床上、床下、衣柜里等所有地方挨个进行寻找,做到不放过任何一个死角,所有的抽屉、存储柜中全部都找遍,形象比喻就是翻个底朝天,然后再寻找下一间,直到找到为止。如果是走迷宫,就是从起点出发,同时进行所有可能路径的寻找,直到某条路径到达终点。与广度优先搜索不同的是,广搜是一条路走到底,深搜就是同时所有可能路径一起搜索,直到有一条路径到达终点,就结束。

(2)图中的定义

从图中某个顶点出发,访问此顶点,然后从V的未被访问的邻接点出发深度优先遍历图,直至图中所有和V有路径相通的顶点都被访问。若图中尚有结点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。

(3)例题

八皇后 Checker Challenge

题目描述

一个如下的 6* 6 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。

上面的布局可以用序列 2 4 6 1 3 5来描述,第 i 个数字表示在第 i 行的相应位置有一个棋子,如下:

行号 1 2 3 4 5 6

列号 2 4 6 1 3 5

这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。

并把它们以上面的序列方法输出,解按字典顺序排列。

请输出前 3 个解。最后一行是解的总个数。

输入格式

一行一个正整数 n,表示棋盘是 n *n大小的。

输出格式

前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。

样例 #1

样例输入 #1

6

样例输出 #1

2 4 6 1 3 5

3 6 2 5 1 4

4 1 5 2 6 3

4

提示

 

【数据范围】

对于 100% 的数据,6<= n <=13。

题目翻译来自NOCOW。

USACO Training Section 1.5

思路

每个皇后会占用他所在的行、列以及两条斜线,所以一行只能放一个皇后,关键是我们要表示出竖线以及斜线的占用方式;

用row[ i ]可以表示第i行是否有了皇后

用t[ i ]=j表示第i行第j列是否已经被占用

确定第 i 行放皇后的位置,搜索每一列,如果(i,j)所在的行、列、上斜线,下斜线都没有被占用,即所有的数据都为0,那就可以放置皇后,更新占用状态,接着搜索下一行放皇后的位置。搜索结束后注意还原。

下图是一个 4*4的坐标表格

1,1

1,2

1,3

1,4

2,1

2,2

2,3

2,4

3,1

3,2

3,3

3,4

4,1

4,2

4,3

4,4

看下标图我们的一得到

上斜线(也就是从(4,1)这个点往点(1,4)的方向,就是“/"):i+j的值是一样的,所以可以用ud[i+j]来表示是否被占用。

下斜线(就是从(4,4)这个点往(1,1)这个点的方向一样,就是“\”):i-j的值都是一样的,加上n是因为下标没有负数,所以加上相同的数,所以用ld[i-j+n]来表示是否被占用。

#include<stdio.h>
int n;
int t[15],row[15],ud[100],ld[100];//用数组t[13]表示皇后放的位置,分别用ud[13]和ld[13]表示上、下对角线
int sum=0,k=0;
int j;
void print()
{
    sum++; //统计总共有多少解
    if(k<=3)  //输出前3个解
        { 
        for(int i=1; i<=n; i++)
            printf("%d ",t[i]);
        printf("\n");
        }

}

void dfs(int i) //i表示第几行
{
    if(i>n)  
    {
        k++;
        print();
        return;
    }
    else
    {

        for(int j=1; j<=n; j++)
        {
            //上斜线的值都是相等的,则可以用ud[i+j]表示,i表示行,j表示列
            //下斜线的坐标相减的值是一样的,这个相减的数字加上相应的行数,即ld[i-j+n]
            if( row[j]==0 && ud[i+j]==0 && ld[i-j+n]==0 )
            {
                t[i]=j;  //在第i行第j列放了第i个皇后
                row[j]=1; //说明这一行已经有了一个皇后
                ud[i+j]=1; //上下两条斜线也都有了一个皇后
                ld[i-j+n]=1;
                dfs(i+1);
                row[j]=0;
                ud[i+j]=0;
                ld[i-j+n]=0;
            }
        }
    }
}

int main()
{
    scanf("%d",&n);
    dfs(1);  //从第一行开始放皇后
    printf("%d",sum);
    k=0;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值