您的位置:首页 > 其它

回溯——矩阵中路径问题(0,1矩阵中最优路径、矩阵中的路径、机器人的运动范围)

2017-03-11 22:13 656 查看
问题一: 给定一个rows*cols 大小的0,1矩阵,给出起点和终点坐标,0可以走,1不可以走,每次只能向上下左右,走一步,求出从起点到终点的最短路径;

解题思路:回溯法解决的经典问题,由于回溯的递归特性,首先要找到递归结束的条件,本题终点就是结束条件(在递归结束判断此路径是否为最优路径)

                    其次,找出递归的条件,本题是坐标x,y的值在合理范围内,并且此点没有走过

                    回溯的位置与条件,当第n个位置四周都为1,都不可以走,则需要回到第n-1位置,只需将第n的位置弹出,设置为没有走过。

//*matrix表示二维0,1矩阵; rows表示矩阵的行数,cols表示矩阵的列数,

//*p1表示起点坐标,p2表示终点坐标,bool *visited用来标记矩阵中的点是否走过没有为0,走过为1;

//*vector<Point>& totalPath 用来盛放最新求出的路径,vector<Point>& bestPath用来盛放最短的路径,这两个参数都加了引用,表示指向实参的位置,而不是重新开辟新的变量,因为在递归调用时,这两个参数会随之改变。

void findBestPath(int *matrix,int rows,int cols,Point p1,Point p2,bool *visited,vector<Point>& totalPath,vector<Point>& bestPath)
{
int x = p1.x, y = p1.y;
if(visited[x*cols + y] == false && matrix[x*cols + y] == 0)
{
totalPath.push_back(p1);
visited[x*cols + y] = true;
if(x == p2.x && y == p2.y)//这个结束判断语句什么时候写
{
//如果是找到的第一条路径,直接添加到bestpath中
int i = 0;
if(bestPath.size() == 0)
{
while(i < totalPath.size())
{
bestPath.push_back(totalPath[i]);
i++;
}
}
else
{
//选择一个最短的路径放到bestPath中
if(bestPath.size() > totalPath.size())
{
bestPath.clear();
i = 0;
while(i < totalPath.size())
{
bestPath.push_back(totalPath[i]);
i++;
}
}
}
}
if((x-1)>= 0){findBestPath(matrix,rows,cols,Point((x-1),y),p2,visited,totalPath,bestPath);}
if((x+1)<rows){findBestPath(matrix,rows,cols,Point((x+1),y),p2,visited,totalPath,bestPath);}
if((y-1)>= 0){findBestPath(matrix,rows,cols,Point(x,(y-1)),p2,visited,totalPath,bestPath);}
if((y+1)<cols){findBestPath(matrix,rows,cols,Point(x,(y+1)),p2,visited,totalPath,bestPath);}
//回溯很重要,理解这个问题,要不要加判断,什么时候写,什么时候不写这个回溯,终点为终止条件
// if(x != p2.x || y != p2.y){
totalPath.pop_back();
visited[x*cols + y] = false;
// }
}
return;
}


<
4000
p>问题二:矩阵中的路径
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如[a b c e s f c s
a d e e]是3*4矩阵,其包含字符串"bcced"的路径,但是矩阵中不包含“abcb”路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。

解题思路和上题相同,主要是终止条件,递归条件不同,要求的返回值情况不同,所以要注意递归的情况的使用

bool flag = false;
bool hasPath(char* matrix, int rows, int cols, char* str)
{   if(matrix == NULL || rows < 1 || cols < 1 || str == NULL)
{
return false;
}
bool *visited = new bool[rows * cols];
memset(visited, 1 ,rows * cols);//默认值为true都可以走
int count = 0;//记录走的点的个数
//找出开始走的点位置
for(int i = 0; i < rows;i++){
for(int j = 0;j < cols;j++){
if(matrix[i*cols + j]== str[count])
{
flag = hasNextNode(matrix,rows,cols,i,j,str,count,visited);
}
}
}
delete[] visited;
return flag;
}

//找出下一个节点
bool hasNextNode(char* matrix, int rows, int cols,int x,int y, char* str,int count,bool * visited)
{
if(str[count] == '\0')//判断str是否已经走完
{
return true;
}
if(x >= 0 && x < rows && y >=0 && y < cols && matrix[x*cols + y] == str[count] && visited[x*cols + y])
{
//matrix[x*cols + y] = '0';//char*的类型值不能修改,所以这么来判断是否走过是不对的。
visited[x*cols + y] = false;//走过不能走了,为false
count++;//将str的位置后移
//找出下一个点上下左右
flag =     hasNextNode(matrix,rows,cols,(x-1),y,str,count,visited)
||  hasNextNode(matrix,rows,cols,(x+1),y,str,count,visited)
||  hasNextNode(matrix,rows,cols,x,(y-1),str,count,visited)
||  hasNextNode(matrix,rows,cols,x,(y+1),str,count,visited);
if(flag == false)//flag不是全局变量
{
--count;
visited[x*cols + y] = true;//回溯,表示此点还可以走
}
}
return flag;
}

问题三:机器人的运动范围

地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。
例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?

解题思路:此题考查思路和上题相同,也考查了整数的每个位数值的和,但是终止条件不是很明确,但是递归的条件很明确,所以只要递归结束就可以返回值,为什么这里不用写回溯的情况呢,还不是很明白,之后看了一篇博客,http://blog.csdn.net/jinzhao1993/article/details/72850641

知道什么时候要回溯,什么时候不要了 和设置的判断变量是不是全局变量。count是全局变量,flag不是全局变量

int movingCount(int threshold, int rows, int cols)
{
if(rows<0 || cols<0 )return 0;
bool *visited = new bool[rows * cols];//定义判断此点是否走过的数组并赋值为true
memset(visited,1,rows * cols);
int count = movingNextPoint(threshold,rows,cols,0,0,visited);
delete []visited;
return count;
}

int movingNextPoint(int threshold, int rows, int cols,int x,int y,bool *visited)
{
int count = 0;
if(x >=0 && x < rows && y >= 0 && y < cols && (sumPerInt(x) + sumPerInt(y))<= threshold && visited[x*cols + y] == true)
{
visited[x*cols + y] = false;//表示此点已经走过不可以再走了
count = 1 + movingNextPoint(threshold,rows,cols,(x-1),y,visited)
+ movingNextPoint(threshold,rows,cols,(x+1),y,visited)
+ movingNextPoint(threshold,rows,cols,x,(y-1),visited)
+ movingNextPoint(threshold,rows,cols,x,(y+1),visited);
}
return count;
}
//求整数各个位数之和
int sumPerInt(int num){
int sum = 0;
while(num > 0){
sum += num % 10;
num /= 10;
}
return sum;
}


这和四叉树的深度很相似,就是四叉树的深度遍历,我当时没有没有联想到~~~~
如果先让你做多叉树的广度深度遍历,然后再让你做这个题,可以就好想一点了。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐