codeup 8.1 搜索专题->深度优先搜索(DFS)

版权声明:原创文章,转载请注明出处 https://blog.csdn.net/hza419763578/article/details/88562231

问题 A: 【递归入门】全排列

时间限制: 1 Sec  内存限制: 128 MB
提交: 661  解决: 414
[提交][状态][讨论版][命题人:外部导入]

题目描述

     排列与组合是常用的数学方法。 
先给一个正整数 ( 1 < = n < = 10 ) 
例如n=3,所有组合,并且按字典序输出: 
1 2 3 
1 3 2 
2 1 3 
2 3 1 
3 1 2 
3 2 1 

输入

输入一个整数n(  1<=n<=10)

输出

输出所有全排列

每个全排列一行,相邻两个数用空格隔开(最后一个数后面没有空格)

样例输入

3

样例输出

1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

方法1.投机取巧next_permutation()

#include<iostream>
#include<algorithm>
using namespace std;
int main(){
	int n;
	int a[11];
	while(cin>>n){
		for(int i=0;i<n;i++) a[i]=i+1;
		do{
			for(int i=0;i<n;i++){
				cout<<a[i]<<" ";
			}
			cout<<endl;
		}while(next_permutation(a,a+n));

	}
	return 0;
}

方法二:老老实实dfs写递归

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

int a[11];
int n;
bool Hash[11];

//index当前排第index位的数  也即是当前排的数在最终结果中的第index位
void dfs(int index){
	if(index==n){
		for(int i=0;i<n;i++){
			cout<<a[i]<<" ";
		}
		cout<<endl;
	}

	for(int i=1;i<=n;i++){
		if(Hash[i]==false){//当前数字没有被排过(本条路径中)
			//i排到index位
			Hash[i]=true;
			a[index]=i;
			dfs(index+1);
			Hash[i]=false;//不排当前数字 排下一个数字(也即是下一次循环的dfs)
		}
	}
}

int main(){
	int a[11];
	while(cin>>n){
		memset(Hash,0,sizeof(Hash));
		for(int i=0;i<n;i++) a[i]=i+1;
		dfs(0);
	}
	return 0;
}

问题 B: 【递归入门】组合的输出

时间限制: 1 Sec  内存限制: 128 MB
提交: 442  解决: 266
[提交][状态][讨论版][命题人:外部导入]

题目描述

排列与组合是常用的数学方法,其中组合就是从n个元素中抽出r个元素(不分顺序且r < = n),我们可以简单地将n个元素理解为自然数1,2,…,n,从中任取r个数。 
现要求你不用递归的方法输出所有组合。 
例如n = 5 ,r = 3 ,所有组合为: 
1 2 3 
1 2 4 
1 2 5 
1 3 4 
1 3 5 
1 4 5 
2 3 4 
2 3 5 
2 4 5 
3 4 5 

输入

一行两个自然数n、r ( 1 < n < 21,1 < = r < = n )。

输出

所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,所有的组合也按字典顺序。

方法1:在一全排列的基础上修改,到r时输出,且下次只排比本次大的数

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

int a[30];
int n,r;
bool Hash[30];

//index当前排第index位的数  也即是当前排的数在最终结果中的第index位
void dfs(int index){
	if(index==r){
		for(int i=0;i<r;i++){
			cout<<a[i]<<" ";
		}
		cout<<endl;
		return;//前面不写return没事 都是false 慢一点而已 此处必须写return
	}

	for(int i=1;i<=n;i++){
		if(index>0&&i<a[index-1]) continue;//小于已经排好的不排
		if(Hash[i]==false){//当前数字没有被排过(本条路径中)
			//i排到index位
			Hash[i]=true;
			a[index]=i;
			dfs(index+1);
			Hash[i]=false;//不排当前数字 排下一个数字(也即是下一次循环的dfs)
		}
	}
}

int main(){
	while(cin>>n>>r){
		memset(Hash,0,sizeof(Hash));
		dfs(0);
	}
	return 0;
}

方法二:简单递归

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

int a[30];
int n,r;

//index当前排第index位的数  也即是当前排的数在最终结果中的第index位
void dfs(int index){
	if(index==r){
		for(int i=0;i<r;i++){
			cout<<a[i]<<" ";
		}
		cout<<endl;
		return;//前面不写return没事 都是false 慢一点而已 此处必须写return
	}

	for(int i=1;i<=n;i++){
		if(index==0||i>a[index-1]){//当前数字没有被排过(本条路径中)
			//i排到index位
			a[index]=i;
			dfs(index+1);
		}
	}
}

int main(){
	int a[11];
	while(cin>>n>>r){
		dfs(0);
	}
	return 0;
}

方法三:典型的m个数中选n个的问题

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

int n,k;
vector<int> vi;

//典型的m个数中选n个的问题
void dfs(int index,int nowK){
	if(nowK==k){	//vi.size()一定等于r
		for(int i=0;i<vi.size();i++){
			cout<<vi[i]<<" ";
		}
		cout<<endl;
		return;
	}

	if(index==n) return;

	//选第index个
	vi.push_back(index+1);//第index个的值就是index+1 懒得开数组存了
	dfs(index+1,nowK+1);
	vi.pop_back();

	//不选第index个
	dfs(index+1,nowK);//总是忘记 第index个不排,就去排第index+1个呀  +1别忘了 ★★★
}

int main(){
	while(cin>>n>>k){
		vi.clear();
		dfs(0,0);
	}
	return 0;
}

方法四:一位大佬巧用pre_permutation()

/*
STL algorithm中prev_permutation函数:
a存储总排列,b存储数字。例如 5 3:
则a数组开始为11100,b数组为12345
开始输出123,a数组前一个排列为11010,输出124
以此类推直到00111输出345结束
*/
#include <cstdio>
#include <algorithm>
using namespace std;
int main(){
	int n, m;
	scanf("%d %d", &n, &m);
	int a[25] = { 0 }, b[25] = { 0 };
	for (int i = 0; i < m; i++)
		a[i] = 1;
	for (int i = 0; i < n; i++)
		b[i] = i + 1;
	for (int i = 0; i < m; i++) {
		printf("%d ", b[i]);
	}
	printf("\n");
	while (prev_permutation(a, a + n)){
		for (int i = 0; i < n; i++)
			if (a[i])
				printf("%d ", b[i]);
		printf("\n");
	}
}

问题 C: 【递归入门】组合+判断素数

时间限制: 1 Sec  内存限制: 128 MB
提交: 828  解决: 246
[提交][状态][讨论版][命题人:外部导入]

题目描述

已知 n 个整数b1,b2,…,bn

以及一个整数 k(k<n)。

从 n 个整数中任选 k 个整数相加,可分别得到一系列的和。

例如当 n=4,k=3,4 个整数分别为 3,7,12,19 时,可得全部的组合与它们的和为:
    3+7+12=22  3+7+19=29  7+12+19=38  3+12+19=34。
  现在,要求你计算出和为素数共有多少种。

例如上例,只有一种的和为素数:3+7+19=29。

输入

第一行两个整数:n , k (1<=n<=20,k<n) 
第二行n个整数:x1,x2,…,xn (1<=xi<=5000000) 

输出

一个整数(满足条件的方案数)。 

样例输入

4 3
3 7 12 19

样例输出

1

判断素数用最常规的做法,用欧式筛法因为基数范围太大反而会超时

#include<iostream>
#include<vector>
#include<cmath>
using namespace std;

int n,k;
vector<int> vi;
int a[25];
int Count;

bool isPrime(long long n){
	for(int i=2;i<=sqrt(n);i++){
		if(n%i==0) return false;
	}
	return true;
}

//典型的m个数中选n个的问题
void dfs(int index,int nowK){
	if(nowK==k){	//vi.size()一定等于r
		int sum=0;
		for(int i=0;i<vi.size();i++){
			sum+=vi[i];
		}
		if(isPrime(sum)){
			Count++;
		}
		return;
	}

	if(index==n) return;

	//选第index个
	vi.push_back(a[index]);//第index个的值就是index+1 懒得开数组存了
	dfs(index+1,nowK+1);
	vi.pop_back();

	//不选第index个
	dfs(index+1,nowK);//总是忘记 第index个不排,就去排第index+1个呀  +1别忘了 ★★★
}

int main(){
	// FindPrime();
	while(cin>>n>>k){
		vi.clear();
		Count=0;
		for(int i=0;i<n;i++){
			cin>>a[i];
		}
		dfs(0,0);
		cout<<Count<<endl;
	}
	return 0;
}

方法二:计算sum也放到递归里,代码简洁好看一点

#include<iostream>
#include <cmath>
using namespace std;
typedef long long ll;

int n,k;
int a[25];
int Count;

bool isprime(ll sum){
	for(int i=2;i<=sqrt(sum);i++){
		if(sum%i==0) return false;
	}
	return true;
}

//选到第index个  共选了nowK个  当前和sum
void dfs(int index,int nowK,ll sum){
	if(nowK==k){
		if(isprime(sum)) {
			Count++;
		}
		return;
	}

	if(index==n) return;//index==n时停止 不是>n  不是自己的代码始终学不会。。

	dfs(index+1,nowK+1,sum+a[index]);
	dfs(index+1,nowK,sum);
}

int main(){
	while(cin>>n>>k){
		Count=0;
		for(int i=0;i<n;i++){
			cin>>a[i];
		}
		dfs(0,0,0);
		cout<<Count<<endl;
	}
	return 0;
}

问题 D: 【递归入门】n皇后 问题(原始的8皇后问题)

时间限制: 1 Sec  内存限制: 128 MB
提交: 364  解决: 177
[提交][状态][讨论版][命题人:外部导入]

题目描述

       会下国际象棋的人都很清楚:皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。如何将8个皇后放在棋盘上(有8 * 8个方格),使它们谁也不能被吃掉!这就是著名的八皇后问题。 

 

输入

一个整数n( 1 < = n < = 10 ) 

输出

每行输出对应一种方案,按字典序输出所有方案。每种方案顺序输出皇后所在的列号,相邻两数之间用空格隔开。如果一组可行方案都没有,输出“no solute!”

样例输入

4

样例输出

2 4 1 3
3 1 4 2

借助next_permutation能解决不少问题

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

int a[11];

int main(){
	int n;
	while(cin>>n){
		if(n<4){
			cout<<"no solute!\n";
			continue;
		} 
		for(int i=0;i<n;i++){
			a[i]=i+1;
		}
		do{
			bool flag=true;
			for(int i=0;i<n;i++){
				for(int j=i+1;j<n;j++){
					if(abs(i-j)==abs(a[i]-a[j])){
						//排列保证不同行不同列
						//斜率保证不同对角线
						flag=false;
					}
				}
			}
			if(flag){
				for(int i=0;i<n;i++){
					cout<<a[i]<<" ";
				}
				cout<<endl;
			}
		}while(next_permutation(a,a+n));
	}
	return 0;
}

问题 E: 【递归入门】出栈序列统计

时间限制: 1 Sec  内存限制: 128 MB
提交: 198  解决: 147
[提交][状态][讨论版][命题人:外部导入]

题目描述

栈是常用的一种数据结构,有n令元素在栈顶端一侧等待进栈,栈顶端另一侧是出栈序列。你已经知道栈的操作有两•种:push和pop,前者是将一个元素进栈,后者是将栈顶元素弹出。现在要使用这两种操作,由一个操作序列可以得到一系列的输出序列。请你编程求出对于给定的n,计算并输出由操作数序列1,2,…,n,经过一系列操作可能得到的输出序列总数。 
 

输入

一个整数n(1<=n<=15) 

输出

一个整数,即可能输出序列的总数目。

样例输入

3

样例输出

5

提示

先了解栈的两种基本操作,进栈push就是将元素放入栈顶,栈顶指针上移一位,等待进栈队列也上移一位,出栈pop是将栈顶元素弹出,同时栈顶指针下移一位。 

用一个过程采模拟进出栈的过程,可以通过循环加递归来实现回溯:重复这样的过程,如果可以进栈则进一个元素,如果可以出栈则出一个元素。就这样一个一个地试探下去,当出栈元素个数达到n时就计数一次(这也是递归调用结束的条件)。 

#include<iostream>
using namespace std;

int num,n;
void dfs(int in,int out){
	if(out>in||out>n||in>n) return;
	if(out==n){
		num++;
		return;
	}
	dfs(in+1,out);
	dfs(in,out+1);
}

int main(){
	while(cin>>n){
		num=0;
		dfs(0,0);
		cout<<num<<endl;
	}
	return 0;
}

问题 F: 【递归入门】走迷宫

时间限制: 1 Sec  内存限制: 128 MB
提交: 480  解决: 159
[提交][状态][讨论版][命题人:外部导入]

题目描述


  有一个n*m格的迷宫(表示有n行、m列),其中有可走的也有不可走的,如果用1表示可以走,0表示不可以走,文件读入这n*m个数据和起始点、结束点(起始点和结束点都是用两个数据来描述的,分别表示这个点的行号和列号)。现在要你编程找出所有可行的道路,要求所走的路中没有重复的点,走时只能是上下左右四个方向。如果一条路都不可行,则输出相应信息(用-l表示无路)。 
  请统一用 左上右下的顺序拓展,也就是 (0,-1),(-1,0),(0,1),(1,0)
 

输入

第一行是两个数n,m( 1 < n , m < 15 ),接下来是m行n列由1和0组成的数据,最后两行是起始点和结束点。 

输出

  所有可行的路径,描述一个点时用(x,y)的形式,除开始点外,其他的都要用“->”表示方向。 
  如果没有一条可行的路则输出-1。

样例输入

5 6
1 0 0 1 0 1
1 1 1 1 1 1
0 0 1 1 1 0
1 1 1 1 1 0
1 1 1 0 1 1
1 1
5 6

样例输出

(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(3,4)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(3,4)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)

提示

【算法分析】 

  用一个a数组来存放迷宫可走的情况,另外用一个数组b来存放哪些点走过了。每个点用两个数字来描述,一个表示行号,另一个表示列号。对于某一个点(x,y),四个可能走的方向的点描述如下表: 

   2 

1  x,y  3 

   4 

  对应的位置为:(x, y-1),(x-1, y),(x, y+1),(x+1, y)。所以每个点都要试探四个方向,如果没有走过(数组b相应的点的值为0)且可以走(数组a相应点的值为1)同时不越界,就走过去,再看有没有到达终点,到了终点则输出所走的路,否则继续走下去。 

  这个查找过程用search来描述如下: 

procedure search(x, y, b, p);{x,y表示某一个点,b是已经过的点的情况,p是已走过的路} 

 begin 

   for i:=1 to 4 do{分别对4个点进行试探} 

   begin 

     先记住当前点的位置,已走过的情况和走过的路; 

     如果第i个点(xl,y1)可以走,则走过去; 

     如果已达终点,则输出所走的路径并置有路可走的信息, 

     否则继续从新的点往下查找search(xl,y1,b1,p1); 

   end; 

 end; 

  有些情况很明显是无解的,如从起点到终点的矩形中有一行或一列都是为0的,明显道路不通,对于这种情况要很快地“剪掉”多余分枝得出结论,这就是搜索里所说的“剪枝”。从起点开始往下的一层层的结点,看起来如同树枝一样,对于其中的“枯枝”——明显无用的节点可以先行“剪掉”,从而提高搜索速度。  

注意:搜索顺序请统一用 左上右下的顺序拓展,也就是 (0,-1),(-1,0),(0,1),(1,0)  否则答案顺序与测试数据顺序不一致
      dfs为了使每次互不影响,每次dfs有几个push就要有几个pop 
      开始dfs之前将起点置为0或者2(非1)。此点必走过,大胆置0(或2 非1)
      Count记录路径总数

 

代码1:

#include<iostream>
#include <utility>
#include <vector>
#include <cstdio>
using namespace std;

const int N = 20;
int a[N][N] = { 0 };
int b[N][N] = { 0 };
int m, n, xs, ys, xe, ye;//m行n列矩阵  起点(xs,ys) 终点(xe,ye)
int dx[4] = { 0,-1,0,1 };//最后一个1写成了-1 结果卡了好久  输出关键值来debug
int dy[4] = { -1,0,1,0 };
vector<pair<int, int> > ans;
int Count;

void dfs(int x, int y) {
	ans.push_back(make_pair(x, y));//能走过来 都是合格的 立刻入队

	if (x == xe&&y == ye) {
		Count++;//顺便记录路径总数
		for (int i = 0;i<ans.size();i++) {
			if (i != 0) printf("->");
			printf("(%d,%d)", ans[i].first, ans[i].second);
		}
		printf("\n");
		return;
	}

	for (int i = 0;i<4;i++) {
		int nx = x + dx[i];
		int ny = y + dy[i];
		if (b[nx][ny]) {
			b[nx][ny] = 0;
			// ans.push_back(make_pair(nx,ny));//此处入队不合适 
			dfs(nx, ny);
			//关键两步 使得dfs每条路径互不干扰成为可能
			ans.pop_back();//异常关键  每次pop()一次 一步一步退到第一次到此的情形 一次push对应一次pop 不会出错
			b[nx][ny] = 1;//很关键
		}
	}
}

int main() {
	// freopen("f.txt", "r", stdin);
	while (scanf("%d%d",&m,&n)!=EOF) {
		for (int i = 1;i <= m;i++) {
			for (int j = 1;j <= n;j++) {
				// cin >> a[i][j];
				scanf("%d",&a[i][j]);
				b[i][j] = a[i][j];
			}
		}
		// cin >> xs >> ys >> xe >> ye;
		scanf("%d%d%d%d",&xs,&ys,&xe,&ye);

		ans.clear();
		Count = 0;
		b[xs][ys]=0;//走过了 开始第一步走的就是这个点 置为0 很重要★★
		dfs(xs, ys);//起点开始 不是0 0
		if (Count == 0) printf("-1\n");
	}

	return 0;
}

代码2

#include<iostream>
#include <utility>
#include <vector>
using namespace std;

const int N=20;
pair<int,int> Start,End;
int n,m,Count;
//请统一用 左上右下的顺序拓展,也就是 (0,-1),(-1,0),(0,1),(1,0)
int dx[4]={0,-1,0,1},dy[4]={-1,0,1,0};
vector<pair<int,int> > ans;//路径结果
int a[N][N]={0};

void dfs(int x,int y){
	ans.push_back(make_pair(x,y));
	if(x==End.first&&y==End.second){
		Count++;
		for(int i=0;i<ans.size();i++){
			if(i!=0) cout<<"->";
			cout<<"("<<ans[i].first<<","<<ans[i].second<<")";
		}
		cout<<endl;
		return;//重要的递归边界可不能忘了
	}

	for(int i=0;i<4;i++){
		int next_x=x+dx[i];
		int next_y=y+dy[i];
		if(a[next_x][next_y]==1){//未走过
			a[next_x][next_y]=2;//走过
			dfs(next_x,next_y);
			//走完还原后 再尝试别的方向
			ans.pop_back();			
			a[next_x][next_y]=1;//还原
		}
	}
}

int main(){
	//int n,m; //千万不要重复定义全局变量
	while(cin>>n>>m){
		//题目要求下标(1,1)开始
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				cin>>a[i][j];
			}
		}
		cin>>Start.first>>Start.second>>End.first>>End.second;
		ans.clear();
		Count=0;
		a[Start.first][Start.second]=2;//此步必走 0不可走 1可走 2走过
		dfs(Start.first,Start.second);
		if(Count==0) cout<<"-1\n";
	}
	return 0;
}

代码3:进一步在迷宫总标出路径

#include<iostream>
#include <utility>
#include <vector>
using namespace std;

const int N=20;
pair<int,int> Start,End;
int n,m,Count;
//请统一用 左上右下的顺序拓展,也就是 (0,-1),(-1,0),(0,1),(1,0)
int dx[4]={0,-1,0,1},dy[4]={-1,0,1,0};
vector<pair<int,int> > ans;//路径结果
int a[N][N]={0};

void Print(int a[N][N]){
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cout<<a[i][j]<<" ";
		}
		cout<<endl;
	}
}

void dfs(int x,int y){
	ans.push_back(make_pair(x,y));
	if(x==End.first&&y==End.second){
		Count++;
		for(int i=0;i<ans.size();i++){
			if(i!=0) cout<<"->";
			cout<<"("<<ans[i].first<<","<<ans[i].second<<")";
		}
		cout<<endl;
		cout<<"path:\n";
		Print(a);
		cout<<endl;
		return;//重要的递归边界可不能忘了
	}

	for(int i=0;i<4;i++){
		int next_x=x+dx[i];
		int next_y=y+dy[i];
		if(a[next_x][next_y]==1){//未走过
			a[next_x][next_y]=2;//走过
			dfs(next_x,next_y);
			//走完还原后 再尝试别的方向
			ans.pop_back();			
			a[next_x][next_y]=1;//还原
		}
	}
}

int main(){
	// int n,m;该死 重复定义n,m
	while(cin>>n>>m){
		//题目要求下标(1,1)开始
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				cin>>a[i][j];
			}
		}
		cin>>Start.first>>Start.second>>End.first>>End.second;
		ans.clear();
		Count=0;
		a[Start.first][Start.second]=2;//此步必走 0不可走 1可走 2走过
		dfs(Start.first,Start.second);
		if(Count==0) cout<<"-1\n";
	}
	return 0;
}

输出结果:

输入:
5 6
1 0 0 1 0 1
1 1 1 1 1 1
0 0 1 1 1 0
1 1 1 1 1 0
1 1 1 0 1 1
1 1
5 6


输出:
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(3,4)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)
path:
2 0 0 1 0 1 
2 2 2 2 2 1 
0 0 2 2 2 0 
1 1 2 2 2 0 
1 1 1 0 2 2 

(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6)
path:
2 0 0 1 0 1 
2 2 2 2 2 1 
0 0 1 2 2 0 
1 1 1 2 2 0 
1 1 1 0 2 2 

(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6)
path:
2 0 0 1 0 1 
2 2 2 2 2 1 
0 0 1 1 2 0 
1 1 1 1 2 0 
1 1 1 0 2 2 

(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)
path:
2 0 0 1 0 1 
2 2 2 2 1 1 
0 0 2 2 1 0 
1 1 2 2 2 0 
1 1 1 0 2 2 

(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6)
path:
2 0 0 1 0 1 
2 2 2 2 1 1 
0 0 1 2 2 0 
1 1 1 1 2 0 
1 1 1 0 2 2 

(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6)
path:
2 0 0 1 0 1 
2 2 2 2 1 1 
0 0 1 2 1 0 
1 1 1 2 2 0 
1 1 1 0 2 2 

(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6)
path:
2 0 0 1 0 1 
2 2 2 2 2 1 
0 0 2 2 2 0 
1 1 1 1 2 0 
1 1 1 0 2 2 

(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6)
path:
2 0 0 1 0 1 
2 2 2 1 1 1 
0 0 2 2 2 0 
1 1 1 1 2 0 
1 1 1 0 2 2 

(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6)
path:
2 0 0 1 0 1 
2 2 2 1 1 1 
0 0 2 2 1 0 
1 1 1 2 2 0 
1 1 1 0 2 2 

(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(3,4)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6)
path:
2 0 0 1 0 1 
2 2 2 2 2 1 
0 0 2 2 2 0 
1 1 2 2 2 0 
1 1 1 0 2 2 

(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6)
path:
2 0 0 1 0 1 
2 2 2 1 1 1 
0 0 2 2 2 0 
1 1 2 2 2 0 
1 1 1 0 2 2 

(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)
path:
2 0 0 1 0 1 
2 2 2 1 1 1 
0 0 2 1 1 0 
1 1 2 2 2 0 
1 1 1 0 2 2 

猜你喜欢

转载自blog.csdn.net/hza419763578/article/details/88562231
8.1