一 ,深度优先搜索代码模板
void dfs()
{
if()
{
return;//收敛或终止条件
}
if(可以剪枝) return
for()
{
if()
{
dfs();
}
}
}
题目索引
1. 给定一个矩阵,求两个目标之间独立路径数
2.
n*n
八皇后棋盘,求
n
不同时,共有多少解法
4.
给定一个候选数和一个数组,从数组选出几个数相加为候选数,找出所有可能的组合解
5.
一个放好了部分数字的数独棋牌,求有多少种方法
真题:
题目1.独立路径数
分析:
设 f[i][j],表示从起点 (1; 1) 到达 (i; j) 的路线条数,则状态转移方程为:
f[i][j]=f[i-1][j]+f[i][j-1]
1.dfs
int uniquePaths(int m, int n)
{
if (m < 1 || n < 1) return 0; // 终止条件
if (m == 1 && n == 1) return 1; // 收敛条件
return uniquePaths(m - 1, n) + uniquePaths(m, n - 1);//
修改 path
}
但是这样会超时。
2.备忘录
int getPaths(int x, int y)
{
if (f[x][y]>0) return f[x][y];
else return f[x][y]=dfs(x,y);
}
参考代码:
class Solution {
public:
int uniquePaths(int m, int n) {
/* 方法一:
带备忘录的递归*/
this->f = vector<vector<int> >(m + 1, vector<int>(n + 1, 0));
return dfs(m, n);
}
private:
vector<vector<int> > f; // 缓存
int
dfs(int x, int y) {
if (x < 1 || y < 1) return 0; // 数据非法,终止条件
if (x == 1 && y == 1) return 1; // 回到起点,收敛条件
return getPaths(x - 1, y) + getPaths(x, y - 1);
}
int
getPaths(int x, int y) {
if (f[x][y] > 0) return f[x][y];
else return f[x][y] = dfs(x, y);
}
/*方法二:使用动态规划.由于只能往下或者往右走,因此(i, j)只会由(i - 1, j)或者(i, j - 1)到达。
int i,j;
int paths[m][n];
memset(paths,0,sizeof(int)*m*n);
for(i=0;i<m;i++)
paths[i][0]=1;
for(j=0;j<n;j++)
paths[0][j]=1;
for(i=1;i<m;i++)
{
for(j=1;j<n;j++)
paths[i][j]=paths[i-1][j]+paths[i][j-1];//(i, j)只会由(i - 1, j)或者(i, j - 1)到达
}
return paths[m-1][n-1];
}
*/
};
Now consider if some obstacles are added to the grids. How many unique paths would there be?
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int> > &obstacleGrid) {
int m=obstacleGrid.size();//行
int n=obstacleGrid[0].size();//列
// 0 行和0 列未使用
this->paths = vector<vector<int> >(m + 1, vector<int>(n + 1, 0));
return dfs(obstacleGrid,m,n);
}
private:
vector<vector<int> > paths;
int dfs(const vector<vector<int> > &obstacleGrid,int x,int y)
{
if(x<1 || y<1) //数据非法
return 0;
if(obstacleGrid[x-1][y-1]) //(x,y)是障碍物,这一句一定要写在收敛条件前面
return 0;
if(x==1 && y==1) //收敛
return 1;
return getPaths(obstacleGrid,x-1,y)+getPaths(obstacleGrid,x,y-1);
}
int getPaths(const vector<vector<int> > &obstacleGrid,int x, int y)
{
if(paths[x][y]>0)
return paths[x][y];
else
return paths[x][y]=dfs(obstacleGrid,x,y);
}
};
2.八皇后
Follow up for N-Queens problem.
Now, instead outputting board configurations, return the total number of distinct solutions.
给定一个n*n的棋盘,问有多少种解,N-Queens需要给出具体的路径,本题只需要给出总个数
分析:
result 记录皇后摆放情况 result[i]表示第i行皇后的位置
cur标记当前位置(行)
res 解的总数
思路:
按行放置皇后,如果放到了第N行,则解数+1.
判断皇后放在当前cur行的val列是否可以 isok(vector<int> &result,int cur,int val);
深度搜索每一种可能解
dfs()
{
for()//就如第0行,每个位置都可以放isok,那么每一种情况都需要判断 所以for里面有dfs
{
if(isok)
{
dfs(,cur+1);//cur标记当前位置,改变路径
}
}
}
代码:
class Solution {
public:
int totalNQueens(int n) {
int ret = 0;//解的个数
vector<int> result(n); //result[n]=m,表示第n行的皇后放在第m列
dfs(ret, result, 0);
return ret;
}
void dfs(int& ret, vector<int>& result, int cur)
{
if(result.size() == cur)
{
++ret;//最后一行可以放,找到一个解
}
else
{
//需找当前行,可以放皇后的列,如果找到,则放置下一行的皇后dfs
for(int i = 0; i < result.size(); ++i)
{
if(isOK(result, cur, i))
{
result[cur] = i;
dfs(ret, result, cur+1);
}
}
}
}
//cur表示在第几行,val表示皇后的列取值,isok来判断cur行的皇后放在val列是否可以
bool isOK(vector<int>& result, int cur, int val)
{
for(int i = 0; i < cur; ++i)
{
if(val == result[i]) ///两个皇后在同一列上
return false;
else if(abs(val - result[i]) == abs(i - cur)) //两个皇后在同一对角线上,两个皇后的列值相减等于行值相减,则在同一对角线
return false;
}
return true;
}
};
3.有效IP地址数目
Given a string containing only digits, restore it by returning all possible valid IP address combinations.
For example:
Given "25525511135"
,
return ["255.255.11.135", "255.255.111.35"]
. (Order does not matter)
分析:
1.给定的字符串,只能分成4段,每段值必须小于255,check(beg,end)
2.我们进行下一步DFS的条件是什么?收敛条件是什么?
我们可以按端搜索,那端的长度取多少?最多取3,每取一个值就判断一下check(start,i),是否可以作为单独的一段,可以的话,就搜索下一段DFS,
那收敛条件就是,已经遍历到了字符串的尾部[start == s.size()],到了段尾[dep == maxDep],则找到一个合法的ip
class Solution {
private:
vector<string> ret;
int pos[4];//pos[n]=i,第n+1端从i个字符串开始,方便输出ip地址
public:
bool
check(string &s, int beg, int end)
{
string ip(s, beg, end - beg + 1);
if (ip.size() == 1)
return "0" <= ip && ip <= "9";
else if (ip.size() == 2)
return "10" <= ip && ip <= "99";
else if (ip.size() == 3)
return "100" <= ip && ip <= "255";
else
return false;
}
void dfs(int dep, int maxDep, string &s, int start)
{
if (dep == maxDep)
{
if (start == s.size())
{
int beg = 0;
string addr;
//根据记录的每一段ip地址的起始位置,加上.号,输出ip地址
for(int i = 0; i < maxDep; i++)
{
string ip(s, beg, pos[i] - beg + 1);
beg = pos[i] + 1;
addr += i == 0 ? ip : "." + ip;//第一段不要.
}
ret.push_back(addr);
}
return;
}
for(int i = start; i < s.size(); i++)
if (check(s, start, i))
{
pos[dep] = i;//记录第i段的起始位置
dfs(dep + 1, maxDep, s, i + 1);
}
}
vector<string> restoreIpAddresses(string s) {
ret.clear();
dfs(0, 4, s, 0);
return ret;
}
};
4.组合数
For example, given candidate set 2,3,6,7
and target 7
,
A solution set is:
[7]
[2, 2, 3]
给定一个候选数和一个数组,找出所有可能的组合解
class Solution {
/*
gap 差距
*/
public:
vector<vector<int> > combinationSum(vector<int> &candidates, int target) {
sort(candidates.begin(), candidates.end());
vector<vector<int> > result; // 最终结果
vector<int> intermediate; // 中间结果
dfs(candidates, target, 0, intermediate, result);
return result;
}
private:
/*dfs(),gap表示离到达target的值,start表示从 candidate中的几个数开始本次搜索*/
void dfs(vector<int>& candidates, int gap, int start, vector<int>& intermediate,vector<vector<int> > &result)
{
if (gap == 0) { // 找到一个合法解
result.push_back(intermediate);
return;
}
for (size_t i = start; i < candidates.size(); i++) { // 扩展状态
if (gap < candidates[i]) return; // 剪枝
intermediate.push_back(candidates[i]); // 执行扩展动作
dfs(candidates, gap - candidates[i], i, intermediate, result);
intermediate.pop_back(); // 撤销动作
}
}
};
5.数独
Write a program to solve a Sudoku puzzle by filling the empty cells.
Empty cells are indicated by the character '.'
.
You may assume that there will be only one unique solution.
A sudoku puzzle...
class Solution {
public:
bool isValidSudoku(vector<vector<char> > &board, int x, int y) {
int row, col;
// Same value in the same column?
for (row = 0; row < 9; ++row) {
if ((x != row) && (board[row][y] == board[x][y])) {
return false;
}
}
// Same value in the same row?
for (col = 0; col < 9; ++col) {
if ((y != col) && (board[x][col] == board[x][y])) {
return false;
}
}
// Same value in the 3 * 3 block it belong to?
for (row = (x / 3) * 3; row < (x / 3 + 1) * 3; ++row) {
for (col = (y / 3) * 3; col < (y / 3 + 1) * 3; ++col) {
if ((x != row) && (y != col) && (board[row][col] == board[x][y])) {
return false;
}
}
}
return true;
}
bool internalSolveSudoku(vector<vector<char> > &board) {
for (int row = 0; row < 9; ++row) {
for (int col = 0; col < 9; ++col) {
if ('.' == board[row][col]) {
for (int i = 1; i <= 9; ++i) {
board[row][col] = '0' + i;
if (isValidSudoku(board, row, col)) {
if (internalSolveSudoku(board)) {
return true;
}
}
board[row][col] = '.';
}
return false;
}
}
}
return true;
}
void solveSudoku(vector<vector<char> > &board) {
internalSolveSudoku(board);
}
};
6.笨笨熊找回家的路
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char map[10][10]={0};
char vis[10][10]={0};//访问记录
int d[4][2]={-1,0,1,0,0,1,0,-1};//4个方向
int queue[10*10];
int m,n;//行列
bool BFS(int x,int y)
{
int front=0,rear=0;//队列头和尾
int cur;//当前节点坐标
cur=x*m+y;
vis[x][y]=1;
queue[rear++]=cur;//当前节点接入队尾
while(front!=rear)
{
cur=queue[front++];//从队首取元素
x=cur/n;y=cur%n;
for(int k=0;k<4;k++)//当前节点的4个领近节点加入队列
{
int nx=x+d[k][0];//nx表示next_x
int ny=x+d[k][1];
if(nx>=0 && nx<m && ny>=0 && ny<n && !vis[nx][ny] && map[nx][ny] == 'H')
{
return true;
}
if(nx>=0 && nx<m && ny>=0 && ny<n && !vis[nx][ny] && map[nx][ny] == '-')
{
int v=nx*m+ny;
queue[rear++]=v;//接入队列尾
vis[nx][ny]=1;
}
}
}
}
bool DFS(int x,int y)
{
if(map[x][y]=='H')
return true;
for(int k=0;k<4;k++)
{
int nx=x+d[k][0];
int ny=y+d[k][1];
if(nx>=0 && nx<m && ny>=0 && ny<n && !vis[nx][ny] && map[nx][ny] == '-')
{
vis[nx][ny]=1;
DFS(nx,ny);
vis[nx][ny]=0;
}
}
}
void main()
{
int i,j,start_x,start_y,res;
scanf("%d\n",&m);//行
scanf("%d\n",&n);//列
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
scanf("%c",&map[i][j]);//别忘了&
}
for(i=0;i<m;i++)//需找B的坐标
{
for(j=0;j<n;j++)
{
if(map[i][j]=='B')
{
start_x=i;
start_y=j;
break;
}
}
}
res=DFS(start_x,start_y);
if(res)
printf("Y\n");
else
printf("N\n");
}
void dfs()
{
if()
{
return;//收敛或终止条件
}
if(可以剪枝) return
for()
{
if()
{
dfs();
}
}
}