教你读懂深度优先的套路

深度优先遍历的基本框架

其中:

a是当前获得的部分解;

k是搜索深度;

input是其它输入;

is_a_solution(a,k,input)判断当前的部分解向量a[1...k]是否是一个符合条件的解;

construct_candidates(a,k,input,c,ncandidates)根据目前状态,构造这一步可能的选择,存入c[]数组,其长度存入ncandidates;

process_solution(a,k,input)对于符合条件的解进行处理,通常是输出、计数等;

make_move(a,k,input)和unmake_move(a,k,input)前者将采取的选择更新到原始数据结构上,后者把这一行为撤销。

填充封闭区域



#include <vector>
#include <iterator>
#include <algorithm>
#include <iostream>
using namespace std;

//构造记录坐标的结构体
struct Point
{
	int x;
	int y;
	Point(int _x, int _y) :x(_x), y(_y){};
	bool operator==(const Point&point)
	{
		if (x == point.x && y == point.y)
		{
			return true;
		}
		return false;
	}
};

//递归函数
void backtrack(vector<vector<char>>&board, int row, int column, Point point, vector<vector<int>>&visit, vector<Point>&output)
{
	//输入有效性判断
	if (point.x < 0 || point.x >= row || point.y < 0 || point.y >= column)
	{
		visit[point.x][point.y] = 1;
		return;
	}
	//递归基
	if (board[point.x][point.y] == 'X')
	{
		visit[point.x][point.y] = 1;
		return;
	}
	output.push_back(point);
	visit[point.x][point.y] = 1;

        //往右深入
	Point point1(point.x, point.y + 1);
	if (point1.y<column)
	{
		if (visit[point1.x][point1.y] == 0)
		{
			backtrack(board, row, column, point1, visit, output);
		}
	}

	//往下深入
	Point point2(point.x + 1, point.y);
	if (point2.x<row)
	{
		if (visit[point2.x][point2.y] == 0)
		{
			backtrack(board, row, column, point2, visit, output);
		}
	}

	//往左深入
	Point point3(point.x, point.y - 1);
	if (point3.y>=0)
	{
		if (visit[point3.x][point3.y] == 0)
		{
			backtrack(board, row, column, point3, visit, output);
		}
	}

        //往上深入
	Point point4(point.x - 1, point.y);
	if (point4.x>=0)
	{
		if (visit[point4.x][point4.y] == 0)
		{
			backtrack(board, row, column, point4, visit, output);
		}
	}
	
}

void FlipOSurrendedByX(vector<vector<char>>&board, int row, int column)
{
	//创建并初始化记录每个位置是否被访问到的数据结构
	vector<vector<int>>visit;
	for (int i = 0; i < board.size(); ++i)
	{
		vector<int>vec1;
		for (int j = 0; j < board[i].size(); ++j)
		{
			vec1.push_back(0);
		}
		visit.push_back(vec1);
	}
	for (int i = 0; i < row; ++i)
	{
		for (int j = 0; j < column; ++j)
		{
			vector<Point>discovered;
			Point point(i, j);
			if (visit[i][j] != 1)
			{
				backtrack(board, row, column, point, visit, discovered);
			}
			if (!discovered.empty())
			{
				for (auto point : discovered)
				{
					if (point.x == 0 || point.x == row - 1 || point.y == 0 || point.y == column - 1)
					{
						discovered.clear();
						break;
					}
				}
				for (auto point : discovered)
				{
					board[point.x][point.y] = 'X';
				}

			}
		}
	}
	return;
}
	int main()
	{

		vector<vector<char>>input;
		const int size = 5;
		for (int i = 0; i < size;++i)
		{
			vector<char>vec1;
			for (int j = 0; j < size;++j)
			{
				char ch;
				cin >> ch;
				vec1.push_back(ch);
			}
			input.push_back(vec1);
		}
		FlipOSurrendedByX(input, size, size);

		for (auto& row:input)
		{
			for (auto& column:row)
			{
				cout << column;
			}
			cout << endl;
		}
		system("pause");
		return 0;
	}

测试结果如下:



生成N个数字的全排列

(1)判断当前解是否为有效解:当前解的大小和输入序列的大小相同;

(2)是则输出;

(3)不是的话,则根据当前的状态,构造下一个可能的取值;

(4)递归逐一的尝试不同的取值。

//判断是否是一个合法的全排列
bool isAnArrangement(vector<int>solution, vector<int>input)
{
	bool result = true;
	if (solution.size() == input.size())
	{
		sort(solution.begin(), solution.end());
		sort(input.begin(), input.end());
		
		for (int i = 0; i < input.size(); ++i)
		{
			if (input[i] != solution[i])
			{
				result = false;
				return result;
			}
		}
	}
	else
	{
		result = false;
	}
	return result;
}

void backtrack(vector<int>solution, vector<int>input)
{
	bool isSolution = isAnArrangement(solution, input);
	if (isSolution)
	{
		copy(solution.begin(), solution.end(), ostream_iterator<int>(cout, " "));
		cout << endl;
		return;
	}
	else
	{
		//构造候选解
		vector<int>candidates(input);
		for (auto itr1 = solution.begin(); itr1 < solution.end();++itr1)
		{
			auto itr2 = find(candidates.begin(), candidates.end(), *itr1);
			if (itr2 != candidates.end())
			{
				candidates.erase(itr2);
			}
		}
		//应注意去重
		sort(candidates.begin(), candidates.end());
		auto itr = unique(candidates.begin(), candidates.end());
		candidates.resize(itr - candidates.begin());
		for (int i = 0; i < candidates.size();++i)
		{
			int value = candidates[i];
			vector<int>solution1(solution);//这里应注意是备份当前的状态进行尝试,不是直接更改当前的状态
			solution1.push_back(value);
			//solution.push_back(candidates[i]);
			backtrack(solution1, input);
		}
	}
}

int main()
{
	vector<int>solution;
	vector<int>input = { 1,2,2,3};
	backtrack(solution, input);
	system("pause");
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值