dfs

比较两个函数的递归过程,加深对递归的理解;

数据结构实验之栈与队列十:走迷宫
Time Limit: 1000 ms Memory Limit: 65536 KiB

Problem Description
一个由n * m 个格子组成的迷宫,起点是(1, 1), 终点是(n, m),每次可以向上下左右四个方向任意走一步,并且有些格子是不能走动,求从起点到终点经过每个格子至多一次的走法数。

Input
第一行一个整数T 表示有T 组测试数据。(T <= 110)

对于每组测试数据:

第一行两个整数n, m,表示迷宫有n * m 个格子。(1 <= n, m <= 6, (n, m) !=(1, 1) ) 接下来n 行,每行m 个数。其中第i 行第j 个数是0 表示第i 行第j 个格子可以走,否则是1 表示这个格子不能走,输入保证起点和终点都是都是可以走的。

任意两组测试数据间用一个空行分开。

Output
对于每组测试数据,输出一个整数R,表示有R 种走法。

Sample Input
3
2 2
0 1
0 0
2 2
0 1
1 0
2 3
0 0 0
0 0 0
Sample Output
1
0
4
Hint
Source

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
using namespace std;
int next[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
int book[101][101];
int e[101][101];
int sum;
void dfs(int x,int y,int n,int m)
{
    if(x==n&&y==m)
    {
        sum++;
        return ;
    }
    int tx,ty;
    for(int i=0;i<=3;i++)
    {
        tx=x+next[i][0];
        ty=y+next[i][1];
        if(tx<1||tx>n||ty<1||ty>m)continue;
        if((e[tx][ty]==0||(tx==n&&ty==m))&&book[tx][ty]==0)
        {
            if(tx==n&&ty==m)
                dfs(tx,ty,n,m);
            else
            {
               book[tx][ty]=1;
               dfs(tx,ty,n,m);
               book[tx][ty]=0;//在这个地方tx,ty是定义在函数里面的,不是函数头上的参变量,所以当执行完上一步的dfs(tx,ty,n,m)的时候,退出,下一步取消标记取消的是这一步的探索,并不是函数参变量x,y的标记;接着看下面的一个类似的题;
            }
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        sum=0;
        memset(book,0,sizeof(book));
        memset(e,0,sizeof(e));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                scanf("%d",&e[i][j]);
            }
        }
        book[1][1]=1;
        dfs(1,1,n,m);
        printf("%d\n",sum);
    }
    return 0;
}


/***************************************************
User name: 
Result: Accepted
Take time: 532ms
Take Memory: 232KB
Submit time: 2018-08-21 17:00:50
****************************************************/

数据结构实验之图论四:迷宫探索
Time Limit: 1000 ms Memory Limit: 65536 KiB

Problem Description
有一个地下迷宫,它的通道都是直的,而通道所有交叉点(包括通道的端点)上都有一盏灯和一个开关;请问如何从某个起点开始在迷宫中点亮所有的灯并回到起点?
Input
连续T组数据输入,每组数据第一行给出三个正整数,分别表示地下迷宫的结点数N(1 < N <= 1000)、边数M(M <= 3000)和起始结点编号S,随后M行对应M条边,每行给出一对正整数,表示一条边相关联的两个顶点的编号。

Output
若可以点亮所有结点的灯,则输出从S开始并以S结束的序列,序列中相邻的顶点一定有边,否则只输出部分点亮的灯的结点序列,最后输出0,表示此迷宫不是连通图。
访问顶点时约定以编号小的结点优先的次序访问,点亮所有可以点亮的灯后,以原路返回的方式回到起点。

Sample Input
1
6 8 1
1 2
2 3
3 4
4 5
5 6
6 4
3 6
1 5
Sample Output
1 2 3 4 5 6 5 4 3 2 1
Hint

Source
xam

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<queue>
using namespace std;
int b[2001];
int book[2001];
int e[3001][3001];
int p,sum;
void dfs(int n,int x,int s)
{
    if(sum==n)return;//判断函数退出的标志不能是x==n,还要返回,当到达N时,并不代表所有的点都访问遍了,只有都访问遍了,一步步返回的时候由于都标记了,所以不会再进入if,sum也不会再增加;
    for(int i=1;i<=n;i++)
    {
        if(e[x][i]==1&&book[i]==0)
        {
            b[++p]=i;
            book[i]=1;
            sum++;
            dfs(n,i,s);
            b[++p]=x;//返回的上一层的x,这时候的x并不是和上一个题一样是定义在函数里面的变量,这个时候的x是函数括号里的参变量,举个例子,拿这个题来说,当i=5进来,一直到i=6才有边,所以x=6进来,发现sum==6了,直接退出,退出后的x变成了5,这时候存进来的是5;上一个题中虽然从上一层退出来了,可是tx,ty还是拓展之后的,这时候取消标记的tx,ty(拓展的),和函数的x,y没有关系;这个题当往后返回,返回到x=1的时候,也就是从x=1时的i=2退出来,还可以把x=1存入数组,但是上面那个题,一步步的返回后只会把他所有的拓展出去的tx,ty都取消标记,但是book[1][1]是没有办法取消标记的;
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m,s;
        p=0;sum=0;
        scanf("%d%d%d",&n,&m,&s);
        memset(book,0,sizeof(book));
        memset(e,0,sizeof(e));
        while(m--)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            e[u][v]=1;
            e[v][u]=1;
        }
        b[++p]=s;
        book[s]=1;
        sum++;
        dfs(n,s,s);
        for(int i=1;i<=p;i++)
        {
            if(i==1)printf("%d",b[i]);
            else printf(" %d",b[i]);
        }
        if(p!=n*2-1)printf(" 0\n");
        else printf("\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值