蓝桥杯第十届真题第五题:七段码

24 篇文章 12 订阅
8 篇文章 1 订阅
该博客介绍了如何利用深度优先搜索(DFS)策略解决七段码数码管表示字符的问题。博主探讨了如何通过单链表存储每个节点及其子节点,并通过DFS生成所有可能的状态。然后,通过队列遍历每个亮着的点,判断是否所有亮着的点都能连成一片,从而确定有效的字符数量。博客提供了具体的C++代码实现,并附带了一个测试数据示例。
摘要由CSDN通过智能技术生成

原题:

题目描述
小蓝要用七段码数码管来表示一种特殊的文字。
七段码上图给出了七段码数码管的一个图示,数码管中一共有 7 段可以发光的二极管,分别标记为 a, b, c, d, e, f, g。小蓝要选择一部分二极管(至少要有一个)发光来表达字符。在设计字符的表达时,要求所有发光的二极管是连成一片的。
例如:b 发光,其他二极管不发光可以用来表达一种字符。
例如:c 发光,其他二极管不发光可以用来表达一种字符。这种方案与上一行的方案可以用来表示不同的字符,尽管看上去比较相似。
例如:a, b, c, d, e 发光,f, g 不发光可以用来表达一种字符。
例如:b, f 发光,其他二极管不发光则不能用来表达一种字符,因为发光的二极管没有连成一片。
请问,小蓝可以用七段码数码管表达多少种不同的字符?

图示,这里的A只与F,B相连,B只与A,G,C相连,在这里我们要判断每个点亮着的时候,与它不连接的灯是否亮着,如果存在,就代表不成字符;

具体的思路是,深搜+存储;

这里的存储有多种方法,很多博主尝试并查集存储,因为每个点都连接着有点,使用并查集的话可以找到与它连接的点,从而找到没有连接的点。

但是这里我发现,使用单链表或许会更好?(绝不是博主看不懂并查集方法并且不愿意学习)

说开始就开始,具体的方法:我们把每一个点当成单链表的头,然后把每一个出点存储在它的下面,这就是为什么我的每一个字母后面跟着数字,数字代表这个位置;

那么我们来看一下对应关系:

                  A   B   C   D  E  F  G   

编号:       1   2   3   4   5   6   7

子个数:    2   3   3   2   3   3   4

子:           2   1   4   3   4   1   2

                  6   3   7   5   6   7   3

                       7   2        7   5   5

                                                6

通过此对应关系,我们可以把每个节点和他的子都存储起来,接下来就是我们的dfs;

dfs的可以把每个点的状态表示出来,我们可以用dfs把每个点是否点亮用0与1表示;这里我们用点小技巧代码如下:

for(int i=0;i<2;i++)
{
	st[k]=i;
	dfs(k+1);
}

st存储每个点的状态,0代表不亮,1代表亮,直接赋值i的话我么就不用打表了,这样通过dfs我们可以模拟出所有情况,接下来只需要对每种状态进行操作即可;

思路是:使用队列,循环存储第一个亮着的点,接着遍历这个点的所有子,将亮着的子加入队列,并且将子灭掉(赋值为0),进行重复循环,直到队列为空结束;

我们通过观察发现,只要能成为字符,那么通过一个点,一定可以遍历到所有亮着的点,所以我们找到第一个亮着的点,接着把这个点和它连着点,和与它连着的点连着的点...都灭掉,肯定的,只要成为字符,那么我们一定可以通过这步操作灭掉所有的点,但是如果不成字符,那么一定会有点不会被灭掉,我们加一层循环判断,只要有亮着的点就不成立即可;

具体代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
queue<int>q;

const int N=50;
int h[10],e[N],ne[50],idx=0;//图的存储 
int st[10],stad[10];//st用来生成亮或者不亮,stad用来进行字符判断 
int n;

void add(int a,int b)
{
	e[idx]=b;
	ne[idx]=h[a];
	h[a]=idx++;
}

int ans=0;//存储答案 

void zh()
{
	for(int i=1;i<=n;i++)
		stad[i]=st[i];
}//复制操作 

void dfs(int k)
{
	if(k==n+1)//dfs结束的条件是我们遍历到了所有点的下一个点 
	{
		zh();//因为这一步要对我们的数组操作,我们必须另开一个一样的数组操作
		     //否则会导致原dfs数组出错 
		int k=-1;//通过k查找第一个亮着的点(其实只要是个亮着的点都可以) 
		for(int i=1;i<=n;i++)
		{
			if(stad[i]==1)
			{
				k=i;
				break;
			}
		}
		
		if(k==-1)
		return ;//全灭的情况,一定不成立; 
		
		
		q.push(k);//加入队列 
		stad[k]=0;//讲这个点灭掉 
		while(!q.empty())
		{
			int m=q.front();
			q.pop();
			for(int j=h[m];j!=-1;j=ne[j])
			{
				if(stad[e[j]]==1)//这步一定要加判断,因为我们只要亮着的点,否则所有点全加进去再循环会造成死循环 
				{
					q.push(e[j]);
					stad[e[j]]=0;
				}
			}
		}//遍历操作 
			
//		cout<<k<<endl;
//		for(int i=1;i<=n;i++)
//			cout<<stad[i]<<' ';
//		cout<<endl;
		
		
		for(int i=1;i<=n;i++)
		{
			if(stad[i]==1) 
			return ;
		}//最终判断,如果全灭,说明只有一个字符,如果还有点亮着(为1),说明点之间不相连 
		
		ans++;
		return ;
	}
	
	for(int i=0;i<2;i++)
	{
		st[k]=i;//小技巧 
		dfs(k+1);
	}//dfs生成我们所有的情况 
}

int main()
{
	memset(h,-1,sizeof(h));//绝对不要忘记初始化 
	
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		int m;
		cin>>m;
		for(int j=0;j<m;j++)
		{
			int k;
			cin>>k;
			add(i,k);
		}
	}//初始化,这一步我们需要把预处理的值输入(填空题,只要答案就行) 
	
	
	dfs(1);//dfs 
	
//	for(int i=1;i<=n;i++)
//	{
//		cout<<i<<':';
//		for(int j=h[i];j!=-1;j=ne[j])
//		{
//			cout<<e[j]<<' ';
//		}
//		cout<<endl;
//	}//这步是我的测试,来判断节点的子是否成功加入; 
	
	cout<<ans;//最后直接输出即可 
	
}

/*
7
2
2 6
3
1 3 7
3 
2 4 7
2
3 5
3 
4 6 7
3
1 5 7
4
2 3 5 6
我们的数据,运行时直接输入即可 
*/

完整代码如上,完结撒花;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值