剪邮票(2016年蓝桥杯)

如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。

请你计算,一共有多少种不同的剪取方法。

剪邮票(2016年蓝桥杯)_第1张图片剪邮票(2016年蓝桥杯)_第2张图片剪邮票(2016年蓝桥杯)_第3张图片


我做这道题就用了两个回溯(思路有点复杂)。。看来回溯对于蓝桥杯很吃香啊。

1.首先用回溯从12个数里面找到5个数

2.每找到5个数把vist数组清0,并且把5个数的坐标分别写入vist数组中

3.然后对vist数组进行回溯,看看从起点开始能不能走完5个数。可以就++否则继续找别的5个数


对回溯不太了解的话可以先试着解决八皇后问题,很经典的题目

总体代码需要改进还有很多

#include
using namespace std;
int a[3][4] = { 0 };
int v[13] = { 0 };
int vist[3][4] = { 0 };
int S = 0;
int fz = 0;
int q[3][4];
int pd2(int i, int j){
	if (i < 0 || j < 0 || i >= 3 || j >= 4 || a[i][j] == 0)
		return 0;
	return 1;
}
int pd3(int v[3][4]){
	for (int i = 0; i < 3; i++){
		for (int j = 0; j < 4; j++)	  {
			if (a[i][j] != 0){
				if (v[i][j] == 0)
					return 0;
			}
		}
	}
	return 1;
}
void dfs(int i, int j){
	if (pd3(vist)){//如果5个数对应的都为1,就满足
		fz = 1;
		return;
	}
	else{
		if (vist[i][j] == 0){//经过判断能到达的坐标都赋值为1
			vist[i][j] = 1;
			if (pd2(i + 1, j))
				dfs(i + 1, j);
			if (pd2(i - 1, j))
				dfs(i - 1, j);
			if (pd2(i, j - 1))
				dfs(i, j - 1);
			if (pd2(i, j + 1))
				dfs(i, j + 1);
		}
	}
}
void f(int i, int j, int sum, int n){//寻找5个数的回溯方法
	if (sum == 5){//找到5个数
		int q1, q2;
		for (int i = 0; i < 3; i++){
			for (int j = 0; j < 4; j++)
			if (a[i][j] != 0){//把第一个数的坐标记录下来,做为下一个回溯的起点
				q1 = i;
				q2 = j;
				break;
			}
		}
		for (int i = 0; i < 3; i++)
		for (int j = 0; j < 4; j++)
			vist[i][j] = 0;//每次vist清0
		dfs(q1, q2);
		if (fz == 1){
			S++;
			fz = 0;
		}
	}
	else{//进行回溯找到5个数
		for (int k = n; k <= 12; k++){
			if (v[k] == 0) {
				v[k] = 1;
				int q1, q2;
				for (int i = 0; i < 3; i++){//这点和乒乓球安排日程和方格填数就不一样了
					for (int j = 0; j < 4; j++)
					if (q[i][j] == k){//他不是像八皇后一样每个位置的数都会变,他有固定的数,所以要把那个数对应的坐标记录下来
						q1 = i; q2 = j;
					}
				}
				a[q1][q2] = k;
				if (q2 == 3)//这点注意换行
					f(q1 + 1, 0, sum + 1, k + 1);
				else f(q1, q2 + 1, sum + 1, k + 1);
				a[q1][q2] = 0;
				v[k] = 0;
			}
		}
	}
}
int main(){
	int k = 0;
	for (int i = 0; i < 3; i++){
		for (int j = 0; j < 4; j++)
			q[i][j] = ++k;
	}//先对数组赋值
	f(0, 0, 0, 1);
	printf("%d", S);
	return 0;
}

代码能改进的地方很多,希望大家指出。一起交流嘛


欢迎大家加入 早起学习群,一起学习一起进步!(群号:642179511

你可能感兴趣的:(回溯,蓝桥杯)