十一届蓝桥杯省赛 C/C++ E-七段码

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

【答案】

80

首先要明确一共有多少种可能。是7!吗?不是的!!!二极管的位置是确定的,不能做全排列。每个灯管要么发光,要么不发光,只能二选一。7根灯管发光相互独立,所以总的发光情况有27-1种,要去掉全灭的情况。

在数据规模不大的情况下,考虑枚举所有情况。这里有两个办法,可以使用递归+回溯的办法,如果不能理解,写个七重循环也能做到这个效果。

void dfs(int x)
{
	if(x>7){
		if(IsConnected()) ans++; //如果连成一片,方案数加一
		init();
		return;
	}
	use[x]=1;
	dfs(x+1);
	use[x]=0;
	dfs(x+1);
}

再然后就是如何判断是否连成一片。我一开始想到的办法是,遍历所有灯管,当一个灯管为亮,判断周围是否有灯管是亮的。代码就不贴了。

先说结论吧,这个方法是错的。如果e,f,b,c亮,他们彼此都有亮的灯管与之相临,但是两个整体是分割的!

网上有题解用到了并查集,但是真的有必要这么复杂吗?上面那个方法错误的原因是,他没有通过已知的亮的灯管,去找所有跟他连成一片的灯管,而是简单判断了周围是否有亮的灯管。这不是典型的搜索题么!dfs走起!

#include <iostream>
using namespace std;

int use[8];
int vis[8]; //记录从一个灯管,所有与之连成一片的亮的灯管
int ans=0;
void init()
{
	for(int i=1;i<=7;i++)
		vis[i]=0;
}
bool Connected() //判断访问所有与之连成一片的亮的灯管是否访问到所有亮的灯管
{
	for(int i=1;i<=7;i++){
		if(use[i]==1&&vis[i]==0){
			return false;
		}
	}
	return true;
}
void Connect(int i) //深度优先搜索与之连成一片的亮的灯管
{
	if(i==1){
		if(use[2]&&!vis[2]){
			vis[2]=1;
			Connect(2);
		}
		if(use[6]&&!vis[6]){
			vis[6]=1;
			Connect(6);
		}
	}else if(i==2){
		if(use[1]&&!vis[1]){
			vis[1]=1;
			Connect(1);
		}
		if(use[3]&&!vis[3]){
			vis[3]=1;
			Connect(3);
		}
		if(use[7]&&!vis[7]){
			vis[7]=1;
			Connect(7);
		}
	}else if(i==3){
		if(use[2]&&!vis[2]){
			vis[2]=1;
			Connect(2);
		}
		if(use[4]&&!vis[4]){
			vis[4]=1;
			Connect(4);
		}
		if(use[7]&&!vis[7]){
			vis[7]=1;
			Connect(7);
		}
	}else if(i==4){
		if(use[5]&&!vis[5]){
			vis[5]=1;
			Connect(5);
		}
		if(use[3]&&!vis[3]){
			vis[3]=1;
			Connect(3);
		}
	}else if(i==5){
		if(use[4]&&!vis[4]){
			vis[4]=1;
			Connect(4);
		}
		if(use[6]&&!vis[6]){
			vis[6]=1;
			Connect(6);
		}
		if(use[7]&&!vis[7]){
			vis[7]=1;
			Connect(7);
		}
	}else if(i==6){
		if(use[1]&&!vis[1]){
			vis[1]=1;
			Connect(1);
		}
		if(use[5]&&!vis[5]){
			vis[5]=1;
			Connect(5);
		}
		if(use[7]&&!vis[7]){
			vis[7]=1;
			Connect(7);
		}
	}else if(i==7){
		if(use[2]&&!vis[2]){
			vis[2]=1;
			Connect(2);
		}
		if(use[3]&&!vis[3]){
			vis[3]=1;
			Connect(3);
		}
		if(use[5]&&!vis[5]){
			vis[5]=1;
			Connect(5);
		}
		if(use[6]&&!vis[6]){
			vis[6]=1;
			Connect(6);
		}
	}
}
bool IsConnected()
{
	int i;
	for(i=1;i<=7;i++){
		if(use[i]) break; //找到任意一个发光灯管
	}
	if(i==8) return false; //灯全灭
	vis[i]=1;
	Connect(i); //从找到的灯管开始找所有与之连成一片的发光灯管
	if(Connected()) return true;
	else return false;
}
void dfs(int x)
{
	if(x>7){
		if(IsConnected()) ans++;
		init();
		return;
	}
	use[x]=1;
	dfs(x+1);
	use[x]=0;
	dfs(x+1);
}
int main()
{
	dfs(1);
	cout<<ans<<endl;
	
	return 0;
} 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值