题目:
题目:
小蓝要用七段码数码管来表示一种特殊的文字。
上图给出了七段码数码管的一个图示,数码管中一共有 7 段可以发光的二
极管,分别标记为 a, b, c, d, e, f, g。
小蓝要选择一部分二极管(至少要有一个)发光来表达字符。在设计字符
的表达时,要求所有发光的二极管是连成一片的。
例如:b 发光,其他二极管不发光可以用来表达一种字符。
例如:c 发光,其他二极管不发光可以用来表达一种字符。
这种方案与上一行的方案可以用来表示不同的字符,尽管看上去比较相似。
例如:a, b, c, d, e 发光,f, g 不发光可以用来表达一种字符。
例如:b, f 发光,其他二极管不发光则不能用来表达一种字符,因为发光
的二极管没有连成一片。
请问,小蓝可以用七段码数码管表达多少种不同的字符?
思路:
大体思路是这样
1.要求多少种不同的表达式,换一种说法a~g所有的灯排成一行,放进一个
一维数组(递归实现指数型枚举),每次从中选取人n个灯,选到的灯变亮,
不选的不亮,这样就把所有情况都包含进来,我们只需判断每一种情况是否
合法,和发则ans++;
2.为了更好的判断所有亮的灯是否联通,把原图转换成一下这种二维图
然后六个方向搜索就行了,哪六个呢:右下、左下、左上、右上、下两格、上两格;
3.注意并不是所有的灯都有以上这六种方向,看原图的灯,如果只有a和g这
两个灯亮了并不满足题意,因为在原图它们不相连,因此a、g、d这个一列
所搜的时候不会有六个方向只会有四个;
代码:
import java.util.Scanner;
public class 七段码 {
static int N=7;
static int ans=0;
static int countdeng=0;//每一次深搜时亮灯的个数
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
//把所有灯的情况全部判断出来,然后判断此时的情况是否合法
//第一步深搜枚举
int []arr=new int[8];
int []vis=new int[8];
dfs(arr,vis,1);
System.out.println(ans);
}
static void dfs(int []arr,int []vis,int level){
if(level>7){
check(arr);
return;
}
//一共就两种情况,一种是要当前这个灯亮,一种是不要,分别深搜就行
vis[level]=1;
arr[level]=1;
dfs(vis,arr,level+1);
vis[level]=0;
arr[level]=0;
dfs(vis,arr,level+1);
}
static void check(int []arr){
//先把此时灯亮的情况,在表格中显示出来,如果某一个灯需要亮
//在二维表格中它对应的数就为1;
int [][]map=new int[6][4];
int [][]tempmap=new int[6][4];
//a
map[1][2]=arr[1];
//b
map[2][3]=arr[2];
//c
map[4][3]=arr[3];
//d
map[5][2]=arr[4];
//e
map[4][1]=arr[5];
//f
map[2][1]=arr[6];
//g
map[3][2]=arr[7];
//我们要看此时灯是否能连起来
//可以还用深搜,先把所有的灯亮的个数记录起来
//然后以其中一个亮点为起点,向其中六个方向深搜
//每找到一个一个可以联通的点总的灯数就减去一
//最后全部搜完后还剩一盏灯亮着就说明当前方案可行,反之则不行
//找总共有多少盏灯亮着
//所欲多次深搜要初始化
countdeng=0;
for(int i=1;i<=5;i++) {
for (int j = 1; j <= 3; j++) {
if (map[i][j] != 0)
countdeng++;
}
}
//找到了所有灯之后,找一个亮灯的点,开始深搜
int flag=0;//只需要找一个点深搜即可,搜一次后就全部停止
for(int i=1;i<=5;i++){
for(int j=1;j<=3;j++) {
if (map[i][j] != 0) {
flag = 1;
check2(map,tempmap, i, j);
break;
}
}
if (flag==1)
break;
}
if(countdeng-1==0)
{
ans++;
}
}
//能走的六个方向
public static int []xx={1,1,-1,-1,-2,2};//2和-2是因为原图中两个边上的相连也算
//转换成二维图就是加-2和加2
public static int []yy={-1,1,-1,1,0,0};
static void check2(int [][]map,int [][]temp,int x,int y){
temp[x][y]=1;//起始点也要标记下
for(int i=0;i<6;i++){
if(y==2&&i>=4){
continue;//这里特判了a g d它们只有四个方向
}
//这一步很重要,因为中间的a,g,d按原图来是不能上下跳的,这样按原图来是不连续的
//然后就是判断是否越界,是否已经找过,是否灯亮
int tempx=x+xx[i];
int tempy=y+yy[i];
//看是否越界
if(tempx>5||tempx<1)
continue;
if(tempy>3||tempy<1)
continue;
//是否找到过
if(temp[tempx][tempy]!=0)
continue;
//判断这个点是否有
if(map[tempx][tempy]==0)
continue;
if (map[tempx][tempy]==1) {
temp[tempx][tempy] = 1;
countdeng--;
check2(map, temp, tempx, tempy);
}
}
return ;
}
}