2016蓝桥 剪邮票

讲述来自: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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值