剪邮票
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
解题思路:
起初思路:如果把12个方格分别作为起始点进行深搜,记录已经遍历方格的个数,达到5时,方案数加1;
后来发现这种方法会统计多中重复的方案;
正确思路:在12个数中取5个数,把这5个数字转换成坐标的形式并进行标记,然后从某个点出发进行深搜,每搜到一个数,清除它的标记,以免重复搜索,最后判断搜到的数字是否等于5,若相等,则说明这5个数联通,方案数加1;
如何从12个数中选取5个数,并保证这种组合是之前没有被选择过的?
答:从第0个位置开始,数字递增,这样就能保证此种组合不会被重复。
比如:1,2,3,4,5;保证后面每一个数字都要比前一个数字大即可。
参考博客:https://blog.youkuaiyun.com/cai_nia/article/details/62233542
源码附上:
#include <bits/stdc++.h>
using namespace std;
int A[5];
int B[3][4];
int n=0;
int dir[][2]={-1,0,0,1,1,0,0,-1};
int ans=0;
int flag;
void dfs2(int x,int y)
{
for(int i=0;i<4;i++)
{
int xx=x+dir[i][0];
int yy=y+dir[i][1];
if(xx>=0&&xx<3&&yy>=0&&yy<4&&B[xx][yy]==1)
{
B[xx][yy]=0;
flag++;
dfs2(xx,yy);
}
}
}
void dfs(int k)
{
if(n==5)
{
memset(B,0,sizeof(B));
int tempX,tempY;
//把数字转换为坐标
for(int i=0;i<5;i++)
{
int x=(A[i]-1)/4;
int y=(A[i]-1)%4;
B[x][y]=1;
if(i==4)
{
B[x][y]=0;
tempX=x;
tempY=y;
}
}
flag=1;
dfs2(tempX,tempY);
if(flag==5)
{
ans++;
}
}
else
{
for(int i=k+1;i<=12;i++)
{
A[n++]=i;
dfs(i);
n--;
}
}
}
int main()
{
dfs(0);
cout<<ans<<endl;
return 0;
}