剪邮票
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
解题思路: 套用一个递归的模板实现12个数中任意5个的组合数,再用图论方面得连通性问题,判定是否相连。
代码如下;
#include<stdio.h>
#include<string.h>
int n=3,m=4;
int a[100],ans;
int vi[12],map[3][4];
int dir[][2]={ {-1,0}, {1,0}, {0,-1}, {0,1} };
void sea(int x,int y)
{
int x1,y1;
for(int i=0;i<4;i++)
{
x1=x+dir[i][0]; y1=y+dir[i][1];
if(x1<0 || y1<0 || x1>n-1 || y1>m-1)
continue ;
map[x1][y1]=1;
}
}
int judge() //判断已经扫描的数,是否够a[]里面的5个
{
for(int i=5;i>0;i--)
if(vi[a[i]-1]!=1)
return 0;
return 1;
}
void comb(int m,int k) //组合函数
{
int i,j;
for(i=m;i>=k;i--)
{
a[k]=i;
if(k>1)
comb(i-1,k-1);
else //当k==1的时候,凑齐了五个数
{
memset(vi,0,sizeof(vi));
memset(map,0,sizeof(map));
sea((a[5]-1)/4,(a[5]-1)%4); //先扫描第一个
vi[a[5]-1]=1;
for(int i=1;i<5;i++) //还剩4个
{
for(j=a[0]-1;j>0;j--) //每次找一个可达的并且未访问的搜索一下
{
if(!vi[a[j]-1] && map[(a[j]-1)/4][(a[j]-1)%4]) //将一维坐标转化为二维的
{
sea((a[j]-1)/4,(a[j]-1)%4);
vi[a[j]-1]=1;
break;
}
}
}
if(judge())
ans++;
}
}
}
int main()
{
ans=0;
a[0]=5;
comb(12,5); //C(12,5)
printf("%d\n",ans);
return 0;
}