剪邮票
如【图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后等于下一行第一个的情况。
答案:116
#include <iostream> using namespace std; int mp[12]= {1,2,3,4,6,7,8,9,11,12,13,14}; int aa[5],vis[5],sum=0; int b[4]= {-1,1,-5,+5}; void dfs(int n) { for(int i=0; i<4; i++) //上下左右遍历 { int t=aa[n]+b[i]; //aa[n] 第 0 1 2 3 4 共5个数 b[i] 为上下左右遍历对应滴数字加减操作 if(t<1||t>14||t==5||t==10) continue; //排除掉出界情况 for(int j=0; j<5; j++) //5个数 if(!vis[j]&&aa[j]==t) //vis[j] 标记第j个数滴状态,是否被遍历过 { //a[j]为新滴遍历到滴数 vis[j]=1; dfs(j); //对新滴数再进行递归,总是可以到其他几个数,因为在for循环滴递归嘛 } } } int main() { for(int a=0; a<12; a++) //暴力列举,从第一行开始从上到下,避免重复 for(int b=a+1; b<12; b++) for(int c=b+1; c<12; c++) for(int d=c+1; d<12; d++) for(int e=d+1; e<12; e++) { aa[0]=mp[a]; //给5个数赋值 aa[1]=mp[b]; aa[2]=mp[c]; aa[3]=mp[d]; aa[4]=mp[e]; for(int i=0; i<5; i++) //初始化 vis[i]=0; vis[0]=1; //从第一个数开始,第一个数状态位为1 dfs(0); //递归开始 int flag=1;; for(int i=0; i<5; i++) { if(vis[i]!=1) //每个数都能被遍历过,则符合题意 { flag=0; break; } } if(flag==0) continue; else sum++; //sum计数+1 } cout<<sum<<endl; //输出结果 return 0; }参考: http://blog.csdn.net/u014552756/article/details/50946197