2022/12/26总结

迷宫

题目描述

给定一个 N \times MN×M 方格的迷宫,迷宫里有 TT 处障碍,障碍处不可通过。

在迷宫中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障碍。

给定起点坐标和终点坐标,每个方格最多经过一次,问有多少种从起点坐标到终点坐标的方案。

输入格式

第一行为三个正整数 N,M,TN,M,T,分别表示迷宫的长宽和障碍总数。

第二行为四个正整数 SX,SY,FX,FYSX,SY,FX,FY,SX,SYSX,SY 代表起点坐标,FX,FYFX,FY 代表终点坐标。

接下来 TT 行,每行两个正整数,表示障碍点的坐标。

输出格式

输出从起点坐标到终点坐标的方案总数。

输入输出样例

输入 #1复制

2 2 1
1 1 2 2
1 2

输出 #1复制

1

说明/提示

对于 100\%100% 的数据,1 \le N,M \le 51≤N,M≤5,1 \le T \le 101≤T≤10,1 \le SX,FX \le n1≤SX,FX≤n,1 \le SY,FY \le m1≤SY,FY≤m。

 1.该题使用深度优先搜索来实现,从起始坐标往下走,每一次一共有四个方位可以考虑,我采用了顺时针的走法,如果向右走不通则向下,向下不通则向左,向左也不通就向上,用一个二维数组来记住每一边走位的偏差值。

2.每一次都要判断是否已经走到了终点,到了计数器num++,否则返回重新找出下一步可以走的位置。

3.判断下一步走的位置是否为边界,是边界的话则采取下一种走法。

4.如果走的位置没有障碍物并且这一步还没有走过,则走到这里来,用数组b标记已走,递归,走下一步,这一步走完后取消这里的标记。

#include"stdio.h"
int a[10][10],b[10][10],c[10][2],n,m,fx,fy,sx,sy,num=0;
void fun(int x,int y,int step)
{
	int next[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
	int tx,ty,k;
	if(x==fx&&y==fy)
	{
		num++;
		return;
	}
	for(k=0;k<=3;k++)
	{
		tx=x+next[k][0];
		ty=y+next[k][1];
		if(tx<1||tx>n||ty<1||ty>m) continue;
		if(a[tx][ty]==0&&b[tx][ty]==0)
		{
			b[tx][ty]=1;
			fun(tx,ty,step+1);
			b[tx][ty]=0;
		}
	}
}
main()
{
	int t,i,j;
	scanf("%d %d %d",&n,&m,&t);
	scanf("%d %d %d %d",&sx,&sy,&fx,&fy);
	for(i=0;i<t;i++)
	scanf("%d %d",&c[i][0],&c[i][1]);
	for(i=0;i<t;i++)
	a[c[i][0]][c[i][1]]=1;
	b[sx][sy]=1;
	fun(sx,sy,0);
	printf("%d",num);
}

填涂颜色

题目描述

由数字 00 组成的方阵中,有一任意形状闭合圈,闭合圈由数字 11 构成,围圈时只走上下左右 44 个方向。现要求把闭合圈内的所有空间都填写成 22。例如:6\times 66×6 的方阵(n=6n=6),涂色前和涂色后的方阵如下:

0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 2 2 1
1 1 1 1 1 1

输入格式

每组测试数据第一行一个整数 n(1 \le n \le 30)n(1≤n≤30)。

接下来 nn 行,由 00 和 11 组成的 n \times nn×n 的方阵。

方阵内只有一个闭合圈,圈内至少有一个 00。

//感谢黄小U饮品指出本题数据和数据格式不一样. 已修改(输入格式)

输出格式

已经填好数字 22 的完整方阵。

输入输出样例

输入 #1复制

6
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1

输出 #1复制

0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 2 2 1
1 1 1 1 1 1

说明/提示

对于 100\%100% 的数据,1 \le n \le 301≤n≤30。

  1.  这个题仿照上面那个题写,用next数组存每一种下一步走法的偏差值。
  2. 主函数中下标i和j都从1开始,目的是将外圈用0包围以此方便使用联通块的方法将不在闭合圈内的0(1围成的闭合圈外)全部赋值为0。因为题目要求我们只需要将闭合圈内的0赋值为2,但是我们反之将闭合圈外的0赋值为2因为这样在进行搜索时更加方便,在输出时判断一下就可以正确输出了。
#include"stdio.h"
int n,a[50][50];
void fun(int x,int y)
{  
    int next[4][2]={{1,0},{0,-1},{-1,0},{0,1}};
	int i,j,k,zx,zy;
	a[x][y]=2;
	for(i=0;i<4;i++)
	{
		zx=x+next[i][0];
		zy=y+next[i][1];
		if(zx>=0&&zx<=n+1&&zy>=0&&zy<=n+1&&a[zx][zy]==0)
		fun(zx,zy);	
	}
}
main()
{
	int i,j;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	for(j=1;j<=n;j++)
	scanf("%d",&a[i][j]);
	fun(0,0);
	for(i=1;i<=n;i++)
	{
	for(j=1;j<=n;j++)
	if(a[i][j]==2) printf("0 ");
	else if(a[i][j]==0) printf("2 ");
	else printf("1 ");
	printf("\n");
	}	
}

 Lake Counting S

题意翻译

由于近期的降雨,雨水汇集在农民约翰的田地不同的地方。我们用一个 N\times M(1\leq N\leq 100, 1\leq M\leq 100)N×M(1≤N≤100,1≤M≤100) 的网格图表示。每个网格中有水(W) 或是旱地(.)。一个网格与其周围的八个网格相连,而一组相连的网格视为一个水坑。约翰想弄清楚他的田地已经形成了多少水坑。给出约翰田地的示意图,确定当中有多少水坑。

输入第 11 行:两个空格隔开的整数:NN 和 MM。

第 22 行到第 N+1N+1 行:每行 MM 个字符,每个字符是 W 或 .,它们表示网格图中的一排。字符之间没有空格。

输出一行,表示水坑的数量。

输入输出样例

输入 #1复制

10 12
W........WW.
.WWW.....WWW
....WW...WW.
.........WW.
.........W..
..W......W..
.W.W.....WW.
W.W.W.....W.
.W.W......W.
..W.......W.

输出 #1复制

3

说明/提示

OUTPUT DETAILS: There are three ponds: one in the upper left, one in the lower left, and one along the right side.

  1.  该题我采用了和上面那个题相同的想法,找出一个个的联通块。
  2. 此题有八个方向需要考虑,同样的,将他们每个方向的偏移量用数组next存下来。
  3. 在主函数里找到每个W联通块的开头,然后调用函数进行搜索,计数器num加一。
  4. 将每走一步找到的W赋值为.方便下一个联通块的搜索。
    #include"stdio.h"
    int n,m,num=0;
    char a[110][110];
    void fun(int x,int y)
    {
    	int i,zx,zy;
    	int next[8][2]={{1,0},{1,1},{0,1},{1,-1},{-1,0},{-1,-1},{0,-1},{-1,1}};
    	a[x][y]='.';
    	for(i=0;i<8;i++)
    	{
    		zx=x+next[i][0];
    		zy=y+next[i][1];
    		if(zx>=0&&zx<n&&zy>=0&&zy<m&&a[zx][zy]=='W')
    		fun(zx,zy);
    	}
    }
    main()
    {
    	int i,j;
    	scanf("%d %d",&n,&m);
    	for(i=0;i<n;i++)
    	{
    	for(j=0;j<m;j++)
    	scanf("%c",&a[i][j]);
    	getchar();
    	}
    	for(i=0;i<n;i++)
    	{
    		for(j=0;j<m;j++)
    		if(a[i][j]=='W') 
    		{
    		fun(i,j);
    		num++;
    		}
    	}	
    	printf("%d",num);
    }

    小结

  • 今天主要主要学习了深度搜索,了解到很多复杂问题都使用到了dfs来解决。
  • 此类题目熟练度不够,还需要多加练习。
  • 同时了解到了dfs代码的一般套路。
void dfs(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
        处理节点;
        dfs(路径,选择列表); // 递归
        回溯,撤销处理结果
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值