蓝桥杯,路径之谜

前言:

        本题使用的是dfs,我个人认为和飞机降落那道题的解法思路相差不大——

http://t.csdnimg.cn/H6CAqicon-default.png?t=N7T8http://t.csdnimg.cn/H6CAq

一、题目解析

用户登录

        题目的意思就是,从入口到出口,对于小明走过的每一个格子,都会使得这个格子对应的行或者列的靶子上的数数字加一。现在给了我们所有靶子上的数字,让我们推断出小明的路径是什么,题目保证了一定有合法的路径。

        下面就来对这个题目所使用的算法做进一步的分析。

二、算法分析

        对于这种搜索类的题目而言,常用的方法无非两种,一种是深搜(dfs),另一种是宽搜(bfs),这两种方法无所谓好坏,只是我一般习惯用深搜。但是在处理最短路径的时候就必须要使用宽搜了。

        那么我们要怎么做呢?试着考虑一下,我们从起点开始搜索,直到我们搜索到终点结束,在搜索到终点的时候,我们判断一个这个终点的合法性,如果合理的话,我们就返回true,否则我们返回false。

        好,现在来逐步实现一下这些步骤和细节点——

        首先的输入,输出的问题,比较简单,我们直接写出。

#include <bits/stdc++.h>

using namespace std;
const int N = 25;
int g[N][N],col[N],row[N];
int n;

int main()
{
	cin>>n;
	for(int i = 0;i<n;i++)scanf("%d",&col[i]);
	for(int i = 0;i<n;i++)scanf("%d",*row[i]);
	int k = 0;
	for(int i = 0;i<n;i++)
	{
		for(int j = 0;j<n;j++)
		{
			g[i][j] = k++;
		}
	}
	
	
	
	return 0;
}

        接下来我们来分析dfs的过程。

        由于题目要求我们每一个格子只能走一次,所以我们需要记录每一个格子的状态,如果它已经被使用过了,我们就不能在遍历它了,否则可能会出现死循环的情况。

        其次就是,如何遍历?我们采取向量的方法,定义了四个方向,从一个点向他的四周扩展,判断其合法性,如果合法的话,就可以继续搜索。(不合法的情况大概有,越界,该点已被搜索,如果走了该点,那么它的行,列对应的数字就会超过题目给我们的数据)

        关键的一点来了,就是如何知道在搜索过程中,这个点的行,列对应的数字是多少呢?

        我们不妨再开两个数组(r[ ],c[ ])来存储这两个信息。

        至于我们的路径,由于它在搜索过程中是不断变化的,我们不妨开一个加长数组vector<int>path,来储存我们的路径。

        思路大致就是这样的,如果大家感兴趣的话,希望大家可以先自行书写一下代码,或者也可以看一下我下边的代码,比对,交流一下。

三、代码呈现

#include <bits/stdc++.h>
using namespace std;
int n;
const int N = 25;
vector<int>path;
int row[N],col[N];
int r[N],c[N];
int g[N][N];
bool state[N][N];
int dx[4] = {1,-1,0,0},dy[4] = {0,0,1,-1};
bool dfs(int sx,int sy)
{
  if(sx==n-1&&sy==n-1)//递归出口 
  {
    for(int i = 0;i<n;i++)
    {
    	if(r[i]!=row[i]||c[i]!=col[i])return false;
	}
	return true;
  }
  for(int i = 0;i<4;i++)//四个方向开始搜索 
  {
    int x = sx+dx[i],y = sy+dy[i];
    if(x<0||x>=n||y<0||y>=n||c[y]==col[y]||r[x] == row[x]||state[x][y])continue;
    state[x][y] = true;
    c[y]++,r[x]++;
    path.push_back(g[x][y]);
    if(dfs(x,y)) return true;//这里相当于一个剪枝的操作,只要我们找到了一个合法的路径,自然就没有必要继续下去了
    path.pop_back();
    c[y]--,r[x]--;
    state[x][y] = false;//都是回溯的过程,注意不要忘记
  }
  return false;//如果能执行这个代码,就说明现在走的路径不是一个合法的路径,所以我们直接返回假即可
}
int main()
{
  cin>>n;
  int k = 0;
  for(int i = 0;i<n;i++)
  {
    for(int j = 0;j<n;j++)
    {
      g[i][j] = k++;
    }
  }
  for(int i = 0;i<n;i++)scanf("%d",&col[i]);
  for(int i = 0;i<n;i++)scanf("%d",&row[i]);
  r[0] = 1,c[0] = 1;
  path.push_back(g[0][0]);
  state[0][0] = true;
  dfs(0,0);
  for(int i = 0;i<path.size();i++)cout<<path[i]<<' ';
  return 0;
}
  • 12
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值