2016蓝桥 剪邮票

来源:互联网 发布:人工智能对社会 编辑:程序博客网 时间:2024/05/18 17:25

讲述来自: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);}

0 0
原创粉丝点击