剪邮票
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
思路:先找到5个数的组合,然后从第一个数字开始遍历,经过上下左右操作检测5个数是否都被访问一遍,如果5个数都可以遍历到则种类+1。
坑点分析:
在原图中向上为-4,向下为+4,向左为-1,向右为+1,但是遇到3 4 5 7 8这种4+1=5但是这种情况不符合,所以重构一下原图:
这样,向上为-5,向下为+5,向左为-1,向右为+1,避免了每行最后一个+1后等于下一行第一个的情况。
思路参考:https://blog.csdn.net/u014552756/article/details/50946197
package 二月十四号真题训练;
/*
剪邮票
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
* */
public class No_7 {
static int arr[]=new int[5];
static int map[]={1,2,3,4,6,7,8,9,11,12,13,14}; //1.坑点:见上面分析
static int vis[]=new int[5];
static int dis[]= {-5,5,-1,1};
static int a,b,c,d,e,count=0;
public static void main(String[] args) {
// TODO Auto-generated method stub
for(a=0;a<12;a++) //a,b,c,d,e分别是五张邮票每一张的下标,相当于从12中随机挑选出5个数来,而且为了保证没有重复,遵循a<b<c<d<e原则进行选取,这样不会出现选取重复现象
for(b=0;b<12;b++)
if(b>a)
for(c=0;c<12;c++)
if(c>b)
for(d=0;d<12;d++)
if(d>c)
for(e=0;e<12;e++)
if(e>d)
{
arr[0]=map[a];
arr[1]=map[b];
arr[2]=map[c];
arr[3]=map[d];
arr[4]=map[e];
for(int i=0;i<5;i++)//因为此题的特殊性,vis不用回溯,所以每次都要把vis数组置0
vis[i]=0;
vis[0]=1; //vis[i]数组记录此点有没有邻居,vis[0]=1,默认是有邻居的
dfs(0);
}
System.out.println(count);
}
private static void dfs(int num) {
// TODO Auto-generated method stub
if(vis[0]==1&&vis[1]==1&&vis[2]==1&&vis[3]==1&&vis[4]==1)
{
count++;return; //当五个点都有邻居,则符合题目要求,count++
}
for(int i=0;i<4;i++)
{
for(int k=0;k<5;k++)
{
if(arr[k]==arr[num]+dis[i]&&vis[k]!=1) //对于每个下标是num的邮票,寻找是否有没被访问过的邻居节点(vis[k]!=1)与其相邻,若找到则标记邻居节点vis[k]=1;并对其进行dfs
{
vis[k]=1;
dfs(k); //注意不要回溯,因为能走到这一步则说明下标为k的邮票肯定有邻居,如果加一条回溯,则这个点便无效作废,但是这个点是有意义的
}
}
}}}