原题:
题目描述
小蓝要用七段码数码管来表示一种特殊的文字。
七段码上图给出了七段码数码管的一个图示,数码管中一共有 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
我们的数据,运行时直接输入即可
*/
完整代码如上,完结撒花;