蓝桥杯--图论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);
	}
}


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

<think>好的,用户想查找与蓝桥杯Java相关的资料或题目。我需要先整理一下已有的引用内容,看看有哪些相关的练习题或示例可以推荐。 首先,查看用户提供的引用内容。引用[1]提到了一个使用Java进行模运算求解的问题,可能涉及日期计算或者周期性题目。引用[2]是关于生成特殊回文数的代码,使用双重循环来构造abba形式的四位数。引用[3]是打印九九乘法表的例子,属于基础循环练习。引用[4]是数列排序的问题,要求使用某种排序算法对输入的数进行排序,这可能涉及到基本的算法实现,比如快速排序或冒泡排序。 接下来,用户需要蓝桥杯Java相关的资料和题目,所以需要将这些引用中的例子进行分类,并可能补充一些常见的蓝桥杯题型。比如,蓝桥杯常考的有基础算法、数据结构、数学问题、字符串处理、动态规划等。根据现有引用,可以推荐基础题目如模运算、回文数生成、排序算法和循环结构练习。 此外,考虑到蓝桥杯的题目通常包含输入输出的处理,需要提醒用户注意Java中如何高效处理输入,比如使用Scanner或BufferedReader。同时,引用中的代码示例都是基础题目,适合初学者练习,可以建议用户多练习类似的题目来巩固基础。 用户可能还需要知道如何系统地准备蓝桥杯,比如分阶段学习,从基础语法到算法优化。可能需要建议参考书籍或在线资源,但当前引用中没有提供,所以暂时不提及,只基于现有资料给出建议。 需要确保回答结构清晰,分点列出推荐的练习题和相关知识点,并生成相关问题,帮助用户进一步探索。同时,注意引用标注的正确性,比如引用[4]对应排序问题,引用[2]对应回文数生成等。</think>### 蓝桥杯Java相关练习与资料整理 以下是基于蓝桥杯Java组常见题型和引用资料的整理,包含基础练习、算法实现及典型题目解析。 --- #### 一、基础语法与数学问题 1. **模运算与周期性计算** 引用[1]中代码通过循环计算 $20^{22} \mod 7$ 的余数,并推导最终结果。此类题目常涉及数论中的模运算性质,例如: ```java // 计算 (20^22 % 7) 并推导结果 int ans = 1; for (int i = 0; i < 22; i++) { ans = ans * 20 % 7; // 每次取模避免溢出 } int result = (6 + ans) % 7; ``` **应用场景**:日期计算、密码学中的周期性分析[^1]。 2. **特殊回文数生成** 引用[2]展示了生成形如 $abba$(四位数)的回文数方法,利用双重循环遍历数字组合: ```java for (int a = 1; a < 10; a++) { for (int b = 0; b < 10; b++) { System.out.println(a * 1000 + b * 100 + b * 10 + a); } } ``` **扩展**:可推广到五位数、六位数回文生成,或增加约束条件(如各位和为定值)[^2]。 --- #### 二、基础算法与数据结构 1. **排序算法实现** 引用[4]要求对输入数列进行排序,需掌握基础排序算法(如冒泡排序、快速排序)。例如,冒泡排序实现: ```java public static void bubbleSort(int[] arr) { for (int i = 0; i < arr.length - 1; i++) { for (int j = 0; j < arr.length - i - 1; j++) { if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } } ``` **注意**:蓝桥杯题目可能限制时间复杂度,需根据数据规模选择算法[^4]。 2. **循环与输出格式** 引用[3]演示了九九乘法表的打印,重点在于循环嵌套和输出对齐: ```java for (int i = 1; i < 10; i++) { for (int j = 1; j <= i; j++) { System.out.printf("%d*%d=%-2d ", j, i, i * j); } System.out.println(); } ``` **技巧**:使用 `printf` 控制格式,使输出更整齐[^3]。 --- #### 三、推荐练习方向 1. **高频题型** - 字符串处理(回文、子串计数) - 动态规划(背包问题、路径规划) - 贪心算法(区间调度、最优分配) - 图论(最短路径、DFS/BFS) 2. **输入输出优化** 蓝桥杯部分题目输入规模较大,建议使用 `BufferedReader` 替代 `Scanner`: ```java BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String[] input = br.readLine().split(" "); ``` ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值