这个是老生常谈的经典图遍历题目了。但是网上大神的代码答案,多多少少都运用了比较复杂的递归实现。这样对于刚入门的小白来说,首先是要花较长时间理解,其次就是好像只会用这个方法做了,很难有普遍性,学不到套路。
所以我一直想找个最简单最基本的BFS递归方法,就能做出来,结果还行。废话不多说,先贴题......(运用c/c++实现)
第一步:如图先稍微改一下题目
第二步:先不管相不相连,先从12筛选出5个彼此不同的数,排除重复数字的可能(如 2 2 6 7 9 13)
在12个数的所有5个数组合中,筛选出随机抽取5个不同数的组合(即12个糖拿5个的所有拿法),则还剩120种可能,存起来。
第三步:每找到一个符合第二步的可能(5个数一组),就利用第一步图中的改进版的上下左右中的关系,筛选出满足 5个数每个数都至少与一个同组数字相邻的的可能。排除那些在本组中有独立数字的可能(即1+4的可能)
例:
排除 5=4+1的可能
- >在排除 4+1 可能后,还剩下 5=2+3 和 5=0+5 两种可能了
5=2+3
5 = 0+5 这正是我们要找的可能
第四步:创建一个 map[15][15] 的图的邻接表,由于第三步筛选时肯定会遍历相邻两个数字的连线两次的,所以正好符合邻接表的条件,这样每种可能在第三步筛选结束后,都建立了一个邻接表(即一个图)。
第五步:调用最基础的DFS算法对第四步生成的邻接表进行遍历,如果这个可能是可以访问5个数的,就是符合题意的,我们的最终结果就加一。
最基本的DFS算法,天然无添加剂!
void DFS(int V1) // 最基础的深度优先遍历:递归实现 V1是访问结点
{
int i;
map[V1][V1] = 1;
nod_num++;
for(i=0;i<15;i++) // 节点数
if(map[V1][i]!=0 && i!=V1) // 查找相邻结点
if(!map[i][i]) // 如果没有访问
DFS(i);
}
完成了!就是那么简单就可以!就是用最简单的递归就实现了哦! 下面贴出完整代码.......
#include<iostream>
#include<string.h>
using namespace std; // 答案:116
int map[15][15],nod_num;
void DFS(int V1) // 最基础的深度优先遍历:递归实现
{
int i;
map[V1][V1] = 1;
nod_num++;
for(i=0;i<15;i++) // 节点数
if(map[V1][i]!=0 && i!=V1) // 查找相邻结点
if(!map[i][i]) // 如果没有访问
DFS(i);
}
int fine(int a[])
{
nod_num=0;
memset(map,0,sizeof(map));
for(int b(0);b<5;b++)
for(int c(0);c<5;c++)
if((a[b] == a[c]+1) || (a[b] == a[c]-5) || (a[b] == a[c]+5) || (a[b] == a[c]-1)) // 第三步:每组的每个元素至少与另一个元素相邻
{
int v1(a[b]),v2(a[c]); // 第四步: 若数字v1与数字v2 相邻,则有两条连线。
// 则经过上个if后 v1-v2 将被遍历为所有相邻的连线
map[v1][v2]=1; // 建立邻接表
map[v2][v1]=1;
}
DFS(a[0]); // 第五步:对第四步生成的邻接表进行遍历,如果这个可能是可以访问5个数的,就是符合题意的
if(nod_num==5) return 1;
return 0;
}
int main() // 外部调用
{
int z[12] = {1,2,3,4,6,7,8,9,11,12,13,14}; // 第一步:图数组
int a[5];
int num(0),num1(0);
for(int i(0);i<12;i++)
for(int j(i+1);j<12;j++)
for(int k(j+1);k<12;k++)
for(int l(k+1);l<12;l++)
for(int m(l+1);m<12;m++) // 第二步:筛选出12个数中随机抽取5个不同数的组合。(用最简单的暴力for就可以解决)
{
a[0]=z[i];
a[1]=z[j];
a[2]=z[k];
a[3]=z[l];
a[4]=z[m];
num1++;
if(fine(a)) num++;
}
cout<<"12个剪切连续5个方法数: "<<num<<endl<<"12个选5个的可能数: "<<num1<<endl;
return 0;
}
如需转载请注明出处!谢谢!