题意:在七个位置上每个位置有发光与否两种状态,只有发光的位置全部联通才属于一个合法情况,求一共有多少种情况合法
填空题,可以考虑并查集做法,做题的时候有些想不起来并查集就用了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);
}
}
感觉代码复杂度还行,就是想了挺长时间不知道比赛的话能不能做出来