【问题描述】
小蓝要用七段码数码管来表示一种特殊的文字。
上图给出了七段码数码管的一个图示,数码管中一共有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;
}