0
点赞
收藏
分享

微信扫一扫

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

老牛走世界 2022-04-03 阅读 83

原题:

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

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

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

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

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

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

通过此对应关系,我们可以把每个节点和他的子都存储起来,接下来就是我们的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
我们的数据,运行时直接输入即可 
*/

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

举报

相关推荐

0 条评论