题目:有一个愚蠢的机器人走进一个w*h的迷宫,迷宫里有空地和陷阱。他想要访问迷宫的每个方格,但是它很笨,只会按照指令的方向走。当机器人不能走的时候,也就是下一步会遇到陷阱、迷宫边界或者访问过的格子,它会向右转90度(顺时针旋转90度,不能访问已经访问过的方格,且在原地只转一次,移动后可获得又一次旋转机会)。请问这个机器人最多可以经过多少个方格。
图片题目来自于http://39.106.164.46/problem.php?id=1021&tdsourcetag=s_pcqq_aiomsg
这一步的主要目的是,将机器人的行走情况分开来讨论
function logic = judge_edge(mat,location)
[i,j]= ind2sub(size(mat),location);
[L,W]= size(mat);
if i == 1 | i == L | j == 1 | j == W
logic = 1;
else
logic = 0;
end
end
对于内部点
% 在执行该算法前,必须得线判断当前点是否为边界点。
% 如果不是边界的话,执行下面程序
% 判断当前方向下一点是否为可行点
% next_location 输出下一点坐标
% a 跟新矩阵
% 考虑矩阵内部时,对于每一个当前点方向,接下来可能有两种走向。四个边界点是特殊点
function [next_location,mat,next_direction] = jude_point(mat,temp_location,direction)
[L,W] = size(mat);
[i,j] = ind2sub(size(mat),temp_location);
% avail = 1;
%% first combination up or right
if direction == 10
if mat(temp_location - 1) == 1
next_location = temp_location - 1;
mat(temp_location) = 0;
next_direction = 10;
else
avail = 1;
end
if exist('avail')
% 往右手边找是否可行
if mat(temp_location + L) == 1
next_location = temp_location + L;
mat(temp_location) = 0;
next_direction = 5;
else
next_direction = 0;
mat(temp_location) = 0;
next_location = temp_location;
end
end
end
%% second combination right or down
if direction == 5
if mat(temp_location + L) == 1
next_location = temp_location + L;
mat(temp_location) = 0;
next_direction = 5;
else % 原方向不可行
avail = 1;
end
if exist('avail') % 如果原方向不可行的话,
% 往右手边找是否可行
if mat(temp_location + 1) == 1
next_location = temp_location + 1;
mat(temp_location) = 0;
next_direction = -10;
else
next_direction = 0;
mat(temp_location) = 0;
next_location = temp_location;
end
end
end
%% third combination down or left
if direction == -10
if mat(temp_location + 1) == 1
next_location = temp_location + 1;
mat(temp_location) = 0;
next_direction = -10;
else
avail = 1;
end
if exist('avail')
% 往左手边找是否可行
if mat(temp_location - L) == 1
next_location = temp_location - L;
mat(temp_location) = 0;
next_direction = -5;
else
%change = 0;
next_direction = 0;
mat(temp_location) = 0;
next_location = temp_location;
end
end
end
%% forth combination left or up
if direction == -5
if mat(temp_location - L) == 1
next_location = temp_location -L;
mat(temp_location) = 0;
next_direction = -5;
else
avail = 0;
end
if exist('avail')
% 往右手边找是否可行(上方)
if mat(temp_location - 1) == 1
next_location = temp_location - 1;
mat(temp_location) = 0;
next_direction = 10;
else
next_direction = 0;
mat(temp_location) = 0;
next_location = temp_location;
end
end
end
end
end
对于边界点
% 重新判断边界
% 如果走不通了,则next_direction = 0 并且 mat(temp_location)=0;
function [ next_direction, next_location,mat] = edge_operation(mat,temp_location,direction)
[L,W] = size(mat);
[i,j] = ind2sub(size(mat),temp_location);
%% 当前方向向上
if direction == 10
if i == 1
if j == W %如果是右上角点的话
next_direction = 0;
next_location = temp_location;
mat(next_location) = 0;
else % 如果不是的话
if mat(temp_location+L) == 1
next_direction = 5;
next_location = temp_location+L;
mat(temp_location) = 0;
else
next_direction = 0;
next_location = temp_location;
mat(next_location) = 0;
end
end
else
% 如果不是最上面一行的话,
if mat(temp_location-1) == 1 % 如果上面行存在可行点则
next_direction = 10;
next_location = temp_location-1;
mat(temp_location) = 0;
else % 如果不存在,则转向
% next_direction = 0;
% next_location = temp_location;
% mat(temp_location) = 2;
change =1;
end
% 如果需要转向的话
if exist('change')
if mat(temp_location+L) == 1 %如果转向可行的话
next_location = temp_location + L;
next_direction = 5;
mat(temp_location) =0;
else % 如果转向不可行的话
next_location = temp_location;
next_direction = 0;
mat(temp_location) = 0;
end
end
end
end
%% 当前方向向下
if direction == -10
if i == L
if j == 1 %如果是左下角点的话
next_direction = 0;
next_location = temp_location;
mat(next_location) = 0;
else % 如果不是的话
if mat(temp_location-L) == 1
next_direction = -5;
next_location = temp_location-L;
mat(temp_location) = 0;
else
next_direction = 0;
next_location = temp_location;
mat(next_location) = 0;
end
end
else
% 如果不是最下一行的话,
if mat(temp_location+1) == 1 % 如果上面行存在可行点则
next_direction = -10;
next_location = temp_location+1;
mat(temp_location) = 0;
else % 如果不存在,则转向
change =1;
end
% 如果需要转向的话
if exist('change')
if mat(temp_location-L) == 1 %如果转向可行的话
next_location = temp_location - L;
next_direction = -5;
mat(temp_location) =0;
else % 如果转向不可行的话
next_location = temp_location;
next_direction = 0;
mat(temp_location) = 0;
end
end
end
end
%% 当前方向向右
if direction == 5
if j == L
if i == W %如果是右下角点的话
next_direction = 0;
next_location = temp_location;
mat(next_location) = 0;
else % 如果不是的话
if mat(temp_location+1) == 1
next_direction = -10;
next_location = temp_location+1;
mat(temp_location) = 0;
else
next_direction = 0;
next_location = temp_location;
mat(next_location) = 0;
end
% next_direction = 0;
% next_location = temp_location;
% change = 1; % 判断是否要转向
end
else
% 如果不是最右侧一行的话,
if mat(temp_location+L) == 1 % 如果上面行存在可行点则
next_direction = 5;
next_location = temp_location+L;
mat(temp_location) = 0;
else % 如果不存在,则转向
% next_direction = 0;
% next_location = temp_location;
% mat(temp_location) = 2;
change =1;
end
% 如果需要转向的话
if exist('change')
if mat(temp_location+1) == 1 %如果转向可行的话
next_location = temp_location + 1;
next_direction = -10;
mat(temp_location) =0;
else % 如果转向不可行的话
next_location = temp_location;
next_direction = 0;
mat(temp_location) = 0;
end
end
end
end
%% 当前方向向左
if direction == -5
if j == 1
if i == 1 %如果是左上角点的话
next_direction = 0;
next_location = temp_location;
mat(next_location) = 0;
else % 如果不是的话
if mat(temp_location-1) == 1
next_direction = 10;
next_location = temp_location-1;
mat(temp_location) = 0;
else
next_direction = 0;
next_location = temp_location;
mat(next_location) = 0;
end
% next_direction = 0;
% next_location = temp_location;
% change = 1; % 判断是否要转向
end
else
% 如果不是最左侧一行的话,
if mat(temp_location-L) == 1 % 如果上面行存在可行点则
next_direction = -5;
next_location = temp_location-L;
mat(temp_location) = 0;
else % 如果不存在,则转向
% next_direction = 0;
% next_location = temp_location;
% mat(temp_location) = 2;
change =1;
end
% 如果需要转向的话
if exist('change')
if mat(temp_location-1) == 1 %如果转向可行的话
next_location = temp_location - 1;
next_direction = 10;
mat(temp_location) =0;
else % 如果转向不可行的话
next_location = temp_location;
next_direction = 0;
mat(temp_location) = 0;
end
end
end
end
end
% yang 2019.3.14
clc
clear all
% 0 表示已经走过的点 1 表示可行点 3 表示禁止点
%% 构造原始矩阵
a = ones(40,40);
% direction:up = 10; down = -10; right = 5;left = -5;
[l,w] = size(a);
n = l*w;
init_station = randperm(n,1);
a(init_station) = 0; % 起始点位置
init_obs = randperm(n,150); % 这个4 可以是随机的,代表障碍物数
% 禁行点 为3
a(init_obs) = 3;
temp_location = init_station;
%%选定初始方向
direction = [10,-10,5,-5];% 分别表示 上 下 右 左
select = randperm(4,1);
direction = direction(select);
%显示颜色
mapcolor(:,:,1) = a/3;
mapcolor(:,:,3) = zeros(l);
%% 迭代
for k = 1:2000
if judge_edge(a,temp_location) % 判断是否为边界,如果是的话,按边界行走方式
[next_direction, next_location,a] = edge_operation(a,temp_location,direction)
temp_location = next_location;
direction = next_direction;
else % 如果不是边界,则进行内部行走运算
[next_location,a,next_direction] = jude_point(a,temp_location,direction);
temp_location = next_location;
direction = next_direction;
end
pause(0.2)
% 循环终止
mapcolor(:,:,2) = a/3;
imagesc(mapcolor);
set(gca,'xtick',[],'ytick',[])
title(['这是第',num2str(k),'步'])
im = frame2im(getframe(gcf));
[I, map] = rgb2ind(im,256);
if i==1
imwrite(I,map,'middle.gif','gif','writeMode','overwrite','loopcount',inf);
else
imwrite(I,map,'middle.gif','gif','WriteMode','append','DelayTime',0.1);
end
if direction == 0
break;
end
end
% 输出个数
temp = a==0;
num = sum(temp(:));
fprintf('一共走过了%d个格子\n',num)
title(['一共走过了',num2str(num),'步'])
第一次写Markdown,发现这东西真好用,可惜渣渣的我代码貌似写的太复杂了,欢迎大神私下交流算法。
以后会放一些交通类的程序代码,欢迎关注!向莫烦大神学习!
Authors
Yang