蓝桥杯--图论5 十一届javaB 七段码(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);
	}
}


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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值