讲述来自:http://blog.csdn.net/u014552756/article/details/50946197#comments感谢作者
剪邮票
如【图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后等于下一行第一个的情况。
作者代码:
#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];
if(t<1||t>14||t==5||t==10) continue;
for(int j=0; j<5; j++)
if(!vis[j]&&aa[j]==t)
{
vis[j]=1;
dfs(j);
}
}
}
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];
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;
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++;
}
cout<<sum<<endl;
return 0;
}
作者思路非常好,尤其重构图部分,确实省了很多功夫,而且代码也讲得很清楚,在阅读了很多次终于体会到一二,在这里我贴一下自己的代码,对数组以及其中的变量名进行重命名,希望阅读起来更方便,再次感谢原文作者
MyCode:
#include<stdio.h>
int all[12]={1,2,3,4,6,7,8,9,11,12,13,14};//全部数
int random[5];//存放随机寻找到的5个数
int visit[5];//是否被访问到的标记
//每个随机取出来的数random[i]对应一个visit[i],表示该数有没有被遍历过
int tag[4]={1,-1,5,-5};//向右+1,向左-1,向下+5,向上-5
void dfs(int n) //n代表随机数的下标random[n],这样random[i]和visit[i]可以一一对应起来
{
int i,j;
int t;
for(i=0;i<4;i++)
{
t=random[n]-tag[i]; //看他的上下左右,减1就是左。加一就是右
if(t<1||t>14||t==5||t==10)continue;//如果这个数t超过了范围就继续找
for(j=0;j<5;j++)//厉害了,找到一个在合理范围的数t
{
if(random[j]==t&&!visit[j])//而且t还是在我们事先找的随机数中,并且还没有遍历到,完美
{
visit[j]=1;//标记一下,这个数我们找过了,而且是符合条件的
dfs(j);//继续找下一个成员
}
}
}
}
int main()
{
int sum=0;//计数
int a,b,c,d,e; //代表all[]数组的下标
int i;//临时变量
for(a=0;a<12;a++)
{
for(b=a+1;b<12;b++)
{
for(c=b+1;c<12;c++)
{
for(d=c+1;d<12;d++)
{
for(e=d+1;e<12;e++)
{
random[0]=all[a];
random[1]=all[b];
random[2]=all[c];
random[3]=all[d];
random[4]=all[e];
//随机找到了五个数
for(i=0;i<5;i++)
{
visit[i]=0; //初始化,现在每一个数都未被遍历
}
visit[0]=1; //从第一个数出发,这个random[0]这个数已经被遍历过了 visit[0]=1
dfs(0);//从第一个数出发,开始找,看看能不能把其余的 4个数random[1-4]都找到,进入函数dfs
//找完了,不知道五个数是否都能遍历到,都能遍历到即visit[]数组的元素都是一,当然这种情况就可取
int flag=1;
for(i=0;i<5;i++) //看每一个random是否都遍历到了,如果是,就sum++,不是就继续找下一批 5个随机数重复过程
{
if(!visit[i])
{
flag=0;
break;
}
}
if(!flag)continue;//这情况不行
else{//这情况可以,sum++
sum++;
}
}
}
}
}
}
printf("%d\n",sum);
}