题目描述
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
小蓝要用七段码数码管来表示一种特殊的文字。
上图给出了七段码数码管的一个图示,数码管中一共有 77 段可以发光的二 极管,分别标记为 a,b,c,d,e,f,g。
小蓝要选择一部分二极管(至少要有一个)发光来表达字符。在设计字符 的表达时,要求所有发光的二极管是连成一片的。
例如:b 发光,其他二极管不发光可以用来表达一种字符。
例如 c发光,其他二极管不发光可以用来表达一种字符。这种方案与上 一行的方案可以用来表示不同的字符,尽管看上去比较相似。
例如:a,b,c,d,e 发光,f,g 不发光可以用来表达一种字符。
例如:b,f 发光,其他二极管不发光则不能用来表达一种字符,因为发光 的二极管没有连成一片。
请问,小蓝可以用七段码数码管表达多少种不同的字符?
dfs选择灯管,并查集判断灯管是否连成一片
#include <iostream>
using namespace std;
const int N=10;
int ans;
//先dfs选择灯管,再并查集处理判断选择的灯管是否是一个字符
int p[N];//并查集父节点
//找根节点
int findx(int x){
if(p[x]!=x) return p[x]=findx(p[x]);//自己不是根节点
else return x; //自己是根节点
}
int used[N];//是否被选择
int e[N][N];//是否连接
//dfs
void dfs(int index){
if(index==7){
//1.出,进行并查集处理,符合条件的加入一个集合,如果是选择的灯管+灯管是连通的-》加入一个集合
//若并查集处理后只有一个集合,则表示选择的灯管都练成一片,可以表示字符,ans++
//这里每次都要记得初始化父节点
//并查集初始化
for(int i=1; i<=7; i++) {
p[i]=i;
}
//并查集合并集合
for(int i=1;i<=7;i++){
for(int j=1;j<=7;j++){
if(used[i]==1&&used[j]==1&&e[i][j]==1){
int fi=findx(i);
int fj=findx(j);
if(fi!=fj) p[fi]=fj;
}
}
}
//并查集查看被选择的灯管里有几个集合
int cnt=0;
for(int i=i;i<=7;i++){
if(used[i]==1&&p[i]==i) cnt++;
}
if(cnt==1) ans++;
return;
}
//2.不选
dfs(index+1);
//3.如果可以选
used[index+1]=1;//选+更新
dfs(index+1);//dfs下一个
used[index+1]=0;//回溯-更新
}
int main()
{
//初始化父节点
for(int i=1;i<=7;i++) p[i]=i;
//初始化连接
e[1][2]=e[1][6]=1;
e[2][7]=e[2][3]=1;
e[3][4]=e[3][7]=1;
e[4][5]=1;
e[6][7]=1;
e[5][6]=e[5][7]=1;
dfs(0);//0起点,下一步对1进行选或不选
printf("%d",ans);
return 0;
}
#include <iostream>
using namespace std;
bool used[10];
int p[10];
int e[10][10];
int ans;
//并查集初始化
void init(){
for(int i=1;i<=7;i++) p[i]=i;//i的根节点是i
}
//并查集找父节点
int findx(int x){
if(p[x]!=x) return p[x]=findx(p[x]);//debug: if(p[x]!=x) p[x]=findx(p[x]);错
// 应该 f(p[x]!=x) return p[x]=findx(p[x]);
else return x;
}
//并查集合并ab
void merge(int a,int b){
//a加入b
int pa=findx(a);
int pb=findx(b);
//如果根节点不同,就合并
if(pa!=pb) p[pa]=pb;//debug:a的根节点更新为b p[a]=b错 p[pa]=pb
}
//dfs出:init ,合并, 查看集合个数 不选 选
//
void dfs(int index){
if(index>7){
//出,进行并查集处理
init();
//合并:如果都被选了并且是连通的,那合并
for(int i=1;i<=7;i++)
for(int j=i+1;j<=7;j++){
if(used[i]&&used[j]&&e[i][j]==1){
merge(i,j);
}
}
//看有几个集合,即几个根节点
int cnt=0;
for(int i=1;i<=7;i++){
if(used[i]&&p[i]==i) cnt++;
}
if(cnt==1) ans++;
return;
}
//不选
dfs(index+1);
//选
used[index]=true;
dfs(index+1);
used[index]=false;
}
int main()
{
e[1][2]=e[1][6]=1;
e[2][7]=e[2][3]=1;
e[3][4]=e[3][7]=1;
e[4][5]=1;
e[6][7]=1;
e[5][6]=e[5][7]=1;
dfs(1);//对第i个管子进行选择
cout<<ans;
return 0;
}