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

来源:互联网 发布:霍纳算法 编辑:程序博客网 时间:2024/04/29 03:03

问题一: 给定一个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;    }


问题二:矩阵中的路径

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如[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;//走过不能走了,为falsecount++;//将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;    }

这和四叉树的深度很相似,就是四叉树的深度遍历,我当时没有没有联想到~~~~

如果先让你做多叉树的广度深度遍历,然后再让你做这个题,可以就好想一点了。。

0 0