蓝桥杯第七届省赛第七题-剪邮票
如图
, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,
中,粉红色所示部分就是合格的剪取。
在看到这个题目时我首先想到的是用DFS来解决,但是在看到图三的时候我发现,DFS取不出来这种剪发,因为题目强调的是所有邮票是连通的但不是只能“一条路走到底”,我们会发现在图三中不管从哪个方向走到6号格子,都会同时面临两个选择,而这两个选择确是这种剪发的组成部分,但是DFS只能选择一个方向一直走下去,不能同时走这两个方向!!在发现了这个bug后我又发现了DFS解决这个题的不足之处,那就是以为图一例,这种剪发在DFS里是两种剪发,分别以2和12为起点,但是还有一些取法,只有一种可能,这就造成了去重的困难,使得单纯的DFS解法失去了用武之地。那怎么解决喃?我想的是可以先将从12个里面选取5个的组合先找出来,然后一个一个的测试其连通性,但是这又遇到了一个问题,那就是如果以一个二维数组来模拟这个方格,那么找出这样的组合又太过于复杂了,因为要两个数字来表示一个格子,要找出5个数字,就需要10个数字来表示,太过于复杂了,于是我在网上发现了一种神奇的操作,自认为远远想不到,于是使用了这种思想将这个题目做出来了,但是还是觉得记录一下较好。
代码:
//这个题用纯粹的DFS会存在一些遍历不到的情况,例如图三,不论从哪个方向走到6,都会面临同时走两个方向的困境,而DFS同时只能选一个方向走到底。
//此题只能先找出5个的组合形式,然后对每个形式用DFS测试其是否联通!!!
//这里使用一种方法用一维数组模拟二维数组及其移动情况!!
#include<iostream>
using namespace std;
int Map[12]={
1,2,3,4,6,7,8,9,11,12,13,14};//注意这里二维数组的特殊取数,只有这样的取数才能用一定的规律去模拟其移动情况!!
int vis[5],Conp[5];
int dir[4]={
-5,+5,-1,+1};
int res=0;
void Dfs(int n){
for(int i=0;i<4;i++){
int temp = Conp[n]+dir[i];
if(temp<1 || temp>14 || temp==10 || temp==5)
continue;
for(int j=0;j<5;j++){
if(vis[j]==0 && Conp[j]==temp){
//这是一种DFS的变形的想法,用来判断多点是否连通!!
vis[j]=1;
Dfs(j);
}
}
}
}
int main(){
for(int a=0;a<12;a++)
for(int b=a+1;b<12;b++)
for(int c=b+1;c<12;c++)
for(int d=c+1;d<12;d++)
for(int e=d+1;e<12;e++){
Conp[0]=Map[a];
Conp[1]=Map[b];
Conp[2]=Map[c];
Conp[3]=Map[d];
Conp[4]=Map[e];
for(int i=0;i<5;i++)
vis[i]=0;
vis[0]=1;
Dfs(0);
int flag=1;
for(int i=0;i<5;i++)
flag*=vis[i];
if(flag==1)
res++;
}
cout<<res<<endl;
return 0;
}
答案:116