剪邮票
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
//检查剪下来的五张邮票是否相邻
public static boolean jiancha(int[][] a,int[] b) {
int bflag=0;
int eflag=0;
boolean flag=false;
while(bflag<=eflag) {
for(int i=0;i<a[b[bflag]].length;i++) {
for(int j=eflag+1;j<=4;j++) {
if(a[b[bflag]][i]==b[j]) {
eflag++;
swap(b,j,eflag);
}
}
}
bflag++;
}
if(eflag==4) flag=true;
return flag;
}
//交换c数组的第a和第b个值
public static void swap(int[] c,int a,int b) {
int temp;
temp=c[a];
c[a]=c[b];
c[b]=temp;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
//根据邮票,手打上的每个邮票与哪几张邮票相邻
int[][] aa= {{1,4},{0,2,5},{1,3,6},{2,7},{0,5,8},{1,4,6,9},{2,5,7,10},{3,6,11},{4,9},{5,8,10},{6,9,11},{7,10}};
int a,b,c,d,e,sum=0,tsum=0;
//从12个选出5个的所有情况
for(a=0;a<8;a++) {
for(b=a+1;b<9;b++) {
for(c=b+1;c<10;c++) {
for(d=c+1;d<11;d++) {
for(e=d+1;e<12;e++) {
int z[] = {a,b,c,d,e};
if(jiancha(aa,z)){//如果都相邻则打印并且sum加一
System.out.println(a+1+" "+(b+1)+" "+(c+1)+" "+(d+1)+" "+(e+1));
sum++;
}
}
}
}
}
}
System.out.println(sum);
}
结果为116种。
这个题困扰了我好几天,我首先犯了一个错误,就是这个从12中选出5个邮票是不需要考虑顺序的,我在穷举的时候算上了这五张邮票的顺序,所以穷举出来的结果多了很多。
我也没搞清楚考虑顺序的数量和不考虑顺序的数量他们之间到底是啥关系,这道题里考虑顺序的数量是不考虑顺序数量的120倍。
我做这题就是先列出来12中选出五个的所有可能,然后对每一种可能判断一次是否满足五个都相邻。判断就是从第一个邮票入栈开始判断,如果剩余邮票有与他相邻的就也入栈,然后判断栈外邮票是否有与栈内其中一个邮票相邻的也入栈,如果所有邮票都能入栈,则五个都相邻。也确实有点像最小生成树prim算法。
其中jiancha方法就是判断过程:有点像栈的思想,先定义栈头和栈尾为0,默认五个数中第一个为栈内元素,然后出栈,判断出栈元素与栈外元素是否相邻,相邻的话就将对应的栈外元素入栈。若栈不为空则继续出栈,知道栈为空或五个元素都入过栈即eflag=4。若都入过栈则这五个元素相邻,否则不相邻。