第七届蓝桥杯省赛A7:剪邮票

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

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

请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

思路分析

全排列加连通块判断。初始化一个3*4的二维数组,然后任选五个位置(保证后面不重复),最后判断这五个位置是否连通即可。

具体实现

首先是从12个数中选择5个数,我们可以初始化一个一维数组b[]={0,0,0,0,0,0,0,1,1,1,1,1},数组b的各个全排列数组中始终有五个数为1,根据这五个数的一维数组标号找到对应的二维数组编号,并将该位置置为1,这样每次排列都会找到五个位置。
然后判断是否连通,首先找到第一个为1的位置,从该位置出发,寻找四个方向上为1且没被访问的点继续深搜。

代码:

#include<bits/stdc++.h>
using namespace std;

int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}}; 
bool vis[3][4]={false};
int b[15],res;
int maze[3][4];

bool in(int x,int y) {   //判断是否越界 
	return x>=0&&x<3&&y>=0&&y<4;
}

//判断连通性 
void dfs(int x,int y) {
	vis[x][y]=true;
	for(int i=0;i<4;i++) {
		int dx=x+dir[i][0];
		int dy=y+dir[i][1];
		if(in(dx,dy)&&!vis[dx][dy]&&maze[dx][dy]==1) {  //找到下一个1就继续dfs 
			dfs(dx,dy);
		}
	}
}

int main() {
	int b[]={0,0,0,0,0,0,0,1,1,1,1,1};  //12选5 
	do {
		memset(maze,0,sizeof(maze));
		memset(vis,false,sizeof(vis));
		for(int i=0;i<3;i++) {
			for(int j=0;j<4;j++) {   //选择了5个数为1 
				if(b[i*4+j]==1) {
					maze[i][j]=1;
				}
			}
		}
		int ans=0;
		for(int i=0;i<3;i++) {
			for(int j=0;j<4;j++) {
				if(maze[i][j]==1&&!vis[i][j]) {  //计算连通块个数 
					ans++;
					dfs(i,j);
				}
			} 
		}
		if(ans==1) {   //只有一个连通块,满足条件 
			res++;
		}
	}while(next_permutation(b,b+12));
	cout<<res;
	return 0;
}

最终答案:116

原创文章 19 获赞 76 访问量 7213

猜你喜欢

转载自blog.csdn.net/Cyril_KI/article/details/105947060
今日推荐