蓝桥杯2020年省赛Java A组-七段码(纯纯DFS解法)

蓝桥杯2020年省赛Java A组-七段码(纯纯DFS解法)

题目描述

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

输出格式

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只输出这个整数,输出多余的内容将无法得分。

答案:80

结题思路

  1. 首先,这是一个图问题,存储方式为邻接矩阵,我们使用0~ 6 来表示 a ~g,然后使用二维的布尔数组arr表示邻接矩阵,相邻则为true
		arr = new boolean[7][7];
		// a b c d e f g
		// 0 1 2 3 4 5 6
		arr[0][1] = arr[0][5] = true;
		arr[1][0] = arr[1][2] = arr[1][6] = true;
		arr[2][1] = arr[2][3] = arr[2][6] = true;
		arr[3][2] = arr[3][4] = true;
		arr[4][3] = arr[4][5] = arr[4][6] = true;
		arr[5][0] = arr[5][4] = arr[5][6] = true;
		arr[6][1] = arr[6][2] = arr[6][4] = arr[6][5] = true;
  1. 我们使用列表path存储已经走过的节点,那么不在path中的节点就是未走过的节点
	private static List<Integer> path = new LinkedList<>();
  1. 从每个顶点出发,采用DFS(深度优先搜索)策略遍历未走过的节点
		for (int i = 0; i < 7; i++) {
			path.clear();//path存储已走过的节点
			path.add(i);//从顶点i出发
			add_result(path, set);//一个节点也作为一种方案
			dfs(path);// dfs剩余节点
		}
	private static void dfs(List<Integer> path) {
		for (int j = 0; j < 7; j++) {
			if (!path.contains(j)&&isOK(path, j)) {//path中没有j且可达j
					path.add(j);
					add_result(path, set);
					dfs(path);
					path.remove(path.indexOf(j));//还原path操作
			}
		}
	}
  1. 对于每一个节点j,如果j未走过且可达[isOK函数],j加入path,作为一种方案,并从这里dfs。还原path,判断j+1

  2. 每走一步,更新path,将path排序后以字符串方式存储于set中,因为set的性质,不会存储相同的字符串,即不会存储相同的方案

  3. set的大小就是不同方案的个数

完整代码

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

public class Main{
	private static boolean[][] arr;
	private static List<Integer> path = new LinkedList<>();
	private static Set<String> set = new HashSet<>();

	public static void main(String[] args) {
		arr = new boolean[7][7];
		// a b c d e f g
		// 0 1 2 3 4 5 6
		arr[0][1] = arr[0][5] = true;
		arr[1][0] = arr[1][2] = arr[1][6] = true;
		arr[2][1] = arr[2][3] = arr[2][6] = true;
		arr[3][2] = arr[3][4] = true;
		arr[4][3] = arr[4][5] = arr[4][6] = true;
		arr[5][0] = arr[5][4] = arr[5][6] = true;
		arr[6][1] = arr[6][2] = arr[6][4] = arr[6][5] = true;
		for (int i = 0; i < 7; i++) {
			path.clear();
			path.add(i);
			add_result(path, set);
			dfs(path);// 从i出发
		}
		System.out.println(set.size());
	}

	private static void dfs(List<Integer> path) {
		for (int j = 0; j < 7; j++) {
			if (!path.contains(j) && isOK(path, j)) {// path中没有j且可达j
				path.add(j);
				add_result(path, set);
				dfs(path);
				path.remove(path.indexOf(j));
			}
		}
	}

	private static boolean isOK(List<Integer> path, int j) {// path是否可达j
		for (int i : path) {
			if (arr[i][j])
				return true;
		}
		return false;
	}

	private static void add_result(List<Integer> path, Set<String> set) {// 新增结果
		path.sort(null);// 先排序,顺序不一样但内容一样作为一种方案
		String s = "";
		for (int i = 0; i < path.size(); i++) {
			s += (char) (path.get(i) + 'a');
		}
		set.add(s);
	}
}

OK,结束啦,欣赏下美景吧
请添加图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值