蓝桥杯--图论5 十一届javaB 七段码(dfs+位运算)

本文介绍了一道关于七个位置发光状态的题目,利用二进制枚举和深度优先搜索(DFS)的方法来找出所有合法的联通状态,并详细解释了代码实现过程。

在这里插入图片描述

题意:在七个位置上每个位置有发光与否两种状态,只有发光的位置全部联通才属于一个合法情况,求一共有多少种情况合法

填空题,可以考虑并查集做法,做题的时候有些想不起来并查集就用了dfs+位运算来做,主要做完看了篇博文说是答案28给我看蒙了,改了半天后来看了别的博文才知道答案是80

当然没有官方答案,网上说是80的比较多吧,自己算完确实也是80


之前在递推部分做过飞行员、开关之类的题,和这题有些类似,因此考虑可以同样使用二进制来枚举状态,简化一下代码

首先因为共有七个位置,每个位置开关两种状态,那么可以使用二进制的表示方法,1开0关,从1枚举至1<<7即27 -1种情况

同时,将a ~ f编号为0 ~ 6,且刚好可以对应二进制的七位,例如二进制数的第5位是1的话代表f开,第3位是0的话代表c关,注意七位二进制的编号是0 ~ 6而不是1 ~ 7

定义两个boolean判定数组vis代表深搜时是否走过该点,st代表该点开关,再定义一个二维boolean数组f[i][j]代表i,j两点是否可以连通

首先初始化连通数组f,将每两个可以连通的f[i][j]标记,接着枚举每个二进制数op,通过位运算来得到每位是 1 的位数i,将st[i]标记为开,同时计数该状态下有多少个点是开状态num

在位运算中选取一个起始点,进行dfs判断该状态是否全部连通,这里可以用到连通块的思路,因为已经记录该状态有多少状态为开的点数,那么进行dfs即是判断从一个起点开始能遍历多少个状态是开的点,如果dfs数量和num相同则说明该状态全部联通,反之则改状态不连通

import java.io.*;
import java.util.*;

public class Main {
	static Scanner tab = new Scanner(System.in);
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
	static int N = 100010;
	
	static boolean f[][]=new boolean [8][8];//图形抽象为二维数组的map
	static boolean vis[]=new boolean[8];//dfs中的标记数组
	static boolean st[]=new boolean [8];//判断状态开关
	
	//深搜查询最大连通块数量
	static int dfs(int x) {
		int num=1;
		vis[x]=true;
		for(int i=0;i<7;i++) {
			if(f[x][i]&&!vis[i]&&st[i])
				num+=dfs(i);
		}
		return num;
	}
	
	public static void main(String[] args) throws IOException {		
		//初始化,将图形间的相连抽象成数组
		//a0 b1 c2 d3 e4 f5 g6
		f[0][1]=f[1][0]=true;
		f[0][5]=f[5][0]=true;
		f[1][6]=f[6][1]=true;
		f[6][5]=f[5][6]=true;
		f[2][3]=f[3][2]=true;
		f[6][2]=f[2][6]=true;
		f[6][4]=f[4][6]=true;
		f[3][4]=f[4][3]=true;
		f[1][2]=f[2][1]=true;
		f[5][4]=f[4][5]=true;
		
		int ans=0;
		for(int op=1;op<1<<7;op++) {
			Arrays.fill(st, false);
			Arrays.fill(vis, false);
			int num=0;//状态为开的块数量
			int start=0;//dfs起点,任意一开点即可
			for(int i=0;i<7;i++) {
				if((op>>i&1)==1) {//位运算
					num++;
					st[i]=true;
					start=i;
				}
			}
			if(num==dfs(start))
				ans++;
		}
		System.out.println(ans);
	}
}


感觉代码复杂度还行,就是想了挺长时间不知道比赛的话能不能做出来

### 关于蓝桥杯 Java B组 深度优先搜索 (DFS) 的相关内容 #### 1. **深度优先搜索(DFS)简介** 深度优先搜索是一种用于遍历或搜索树或图的算法。该算法沿着树的深度遍历节点,尽可能深地探索每条分支[^4]。 #### 2. **蓝桥杯中的 DFS 应用场景** 在蓝桥杯比赛中,DFS 常被用来解决涉及树、图或其他复杂数据结构的问题。例如,在引用[3]中提到了一些典型问题,包括但不限于: - 密码学中的 RSA 解密。 - 字符串子序列问题。 - 数组修改策略。 这些问题可能需要通过 DFS 来枚举所有可能性或者优化路径选择[^3]。 #### 3. **Java 实现 DFS 示例** 以下是一个基于树结构的经典 DFS 题目实现: 假设我们需要在一个无向连通图上找到某个特定目标节点的所有可达路径。 ```java import java.util.*; public class DFSDemo { private static List<List<Integer>> adjacencyList; private static boolean[] visited; public static void main(String[] args) { int n = 6; // 节点数量 adjacencyList = new ArrayList<>(); for (int i = 0; i <= n; i++) { adjacencyList.add(new ArrayList<>()); } // 构造邻接表表示的图 addEdge(1, 2); addEdge(1, 3); addEdge(2, 4); addEdge(2, 5); addEdge(3, 6); visited = new boolean[n + 1]; System.out.println("从节点 1 开始的 DFS:"); dfs(1); // 从节点 1 开始执行 DFS } private static void addEdge(int u, int v) { adjacencyList.get(u).add(v); adjacencyList.get(v).add(u); } private static void dfs(int node) { visited[node] = true; System.out.print(node + " "); for (Integer neighbor : adjacencyList.get(node)) { if (!visited[neighbor]) { dfs(neighbor); } } } } ``` 上述代码展示了如何利用递归方式完成 DFS 遍历操作。此程序构建了一个简单的无向图,并打印出从指定起点出发访问的所有节点顺序。 #### 4. **常见习题与解析** 以下是几个常见的蓝桥杯 DFS 类型题目及其解决方案概述: ##### (1)**迷宫最短路径问题** 给定一个二维矩阵代表迷宫地图,“.” 表示可以通过的位置,“#” 则不可通行。求从起始位置到达终点所需的最少步数。 可以采用 BFS 或者带记忆化的 DFS 方法来解决问题。这里推荐使用 DFS 结合剪枝技术减少不必要的状态空间扩展[^1]。 ##### (2)**岛屿的最大面积** 输入由 '0' 和 '1' 组成的网格,其中 '1' 表示陆地而 '0' 是水体。找出最大连续区域内的 '1' 所构成的岛大小。 对于此类问题,通常先定位每一个未访问过的 ‘1’ ,然后调用一次完整的 DFS 探索整个相连部分并记录其规模[^2]。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值