蓝桥杯七段码

文章讨论了如何使用深度优先搜索(DFS)配合并查集算法,解决用七段码数码管表示特定字符的问题。通过选择二极管并确保它们连成一片来表达不同的字符,计算出可用的字符种类数量。程序通过初始化并查集,然后进行DFS遍历和连接判断,最终得出答案。
摘要由CSDN通过智能技术生成

题目描述

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

小蓝要用七段码数码管来表示一种特殊的文字。

上图给出了七段码数码管的一个图示,数码管中一共有 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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值