题目描述
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
这个题我先是用的dfs来做,但是写到后面发现剪枝太麻烦了,考虑的因素太多,然后参考了一些大佬的思路写了两种方法。
方法一(bfs):
先绘制地图1~12,然后枚举5个不同数字,这五个不同数字都对应一个坐标,把这5个坐标进行标记,在进行dfs。最后判断这五个位置是否有没走过的即可。
答案:116
代码:
#include<stdio.h>
#include<queue>
using namespace std;
int mp[3][4],arr[5];//mp地图数组;arr升序数组,选取5个数
bool vis[3][4];
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
struct Node{
int x,y;
}n;
bool bfs()
{
int num=0,x,y;
for(int i=0;i<3;i++)
for(int j=0;j<4;j++)
if(arr[num]==mp[i][j]) vis[i][j]=true,num++,x=i,y=j;//arr数组里面存的是升序数字 ,所以可以顺序遍历。
else vis[i][j]=false;
n.x=x;//从最后一个数字开始遍历
n.y=y;
queue<Node>q;
q.push(n);
vis[x][y]=false;
while(!q.empty())
{
Node res=q.front();
q.pop();
for(int i=0;i<4;i++)
{
int dx=res.x+dir[i][0];
int dy=res.y+dir[i][1];
if(!vis[dx][dy]||dx<0||dy<0||dx>=3||dy>=4) continue;
vis[dx][dy]=false;
n.x=dx;
n.y=dy;
q.push(n);
}
}
for(int i=0;i<3;i++)
for(int j=0;j<4;j++)//如果是dfs没走到的数字,则不满足条件
if(vis[i][j]) return false;
return true;
}
int main()
{
for(int i=0;i<3;i++)
for(int j=0;j<4;j++)
mp[i][j]=i*4+j+1;
int cnt=0;
for(arr[0]=1;arr[0]<13;arr[0]++)
for(arr[1]=arr[0]+1;arr[1]<13;arr[1]++)
for(arr[2]=arr[1]+1;arr[2]<13;arr[2]++)
for(arr[3]=arr[2]+1;arr[3]<13;arr[3]++)
for(arr[4]=arr[3]+1;arr[4]<13;arr[4]++)
if(bfs()) cnt++;
printf("%d",cnt);
return 0;
}
方法二(堆栈):
从12个数字中选取5个升序数字,将第一个数放进栈,然后将栈顶元素出栈,跟他满足相连条件的其他数一并入栈。依次进行上次操作。最后判断这五个数字有没有没进入栈的情况即可。
代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stack>
using namespace std;
int arr[5];
bool vis[5];
bool cheak(int i,int j)//判断是否满足条件
{
if((i==4&&j==5) || (i==5&&j==4)) return false;
if((i==8&&j==9) || (i==9&&j==8)) return false;
if(abs(i-j)==1 || abs(i-j)==4) return true;
return false;
}
bool slove()
{
memset(vis,false,sizeof(vis));
stack<int>s;
s.push(arr[0]);
vis[0]=true;
while(!s.empty())
{
int res=s.top();
s.pop();
for(int i=0;i<5;i++)
{
if(vis[i]||!cheak(res,arr[i])) continue;
vis[i]=true;
s.push(arr[i]);
}
}
for(int i=0;i<5;i++)//是否有没入栈的条件
if(!vis[i]) return false;
return true;
}
int main()
{
int cnt=0;
for(arr[0]=1;arr[0]<13;arr[0]++)
for(arr[1]=arr[0]+1;arr[1]<13;arr[1]++)
for(arr[2]=arr[1]+1;arr[2]<13;arr[2]++)
for(arr[3]=arr[2]+1;arr[3]<13;arr[3]++)
for(arr[4]=arr[3]+1;arr[4]<13;arr[4]++)
if(slove()) cnt++;
printf("%d",cnt);
return 0;
}