emmmm,对于连通块,其实有很多方式求解。这里我还是以那个剪邮票的题目为例子来简述怎么用python操作。
主要思想
遍历一遍某点的周围连通的块
遍历给出的块
判断它们是不是相等的,打标记,相等就连通块个数+1
再遍历给出块中剩下的块
如果都相等,连通块个数=给出的块的个数
DFS判断是否是连通块
一般来说,DFS判断连通块无非就是从一个点开始往它的四面八方(上下左右)走,能走到的地方属于该点的连通块集合,判断给出的数组的其他点在不在这个集合里面就行了。
在这个剪邮票的题目中原始的数组为mp=[1,2,3,4,5,6,7,8,9,10,11,12](因为是用排列组合求出的可能存在的连通块,所以这里不是用坐标传入dfs,而是用数值传入dfs),同一行的相邻数字相差1(左右走),同一列的相邻数字相差4(上下走)。
但是,很显然5和9不满足这一点,如果5-1那就走到4那边去了,就不是我们希望的上下走,9同理。
为了克服这一点,我们把数组改成mp=[1,2,3,4,6,7,8,9,11,12,13,14]
邮票集变成:
1 | 2 | 3 | 4 |
---|---|---|---|
6 | 7 | 8 | 9 |
11 | 12 | 13 | 14 |
这样在边界处的6±1就只会往5和7的方向走,到时候直接把5略去就好。
修正后的方向集为d=[1,-1,5,-5]代表上下左右四个方向。
mp=[1,2,3,4,6,7,8,9,11,12,13,14]
cut=[0]*5#剪下的数字
vis=[0]*5#标记数组
#用来记录总共可
tot=0
def dfs(u):
#往上下左右走
d=[-1,1,-5,5]
for i in range(4):
#上下左右走就是加减数字
x=cut[u]+d[i]
if x<1 or x>15 or x==5 or x==10:
continue
for j in range(5):
if vis[j]==0 and cut[j]==x:
vis[j]=1
dfs(j)
for a in range(12):
for b in range(a+1,12):
for c in range(b+1,12):
for d in range(c+1,12):
for e in range(d+1,12):
cut[0]=mp[a]
cut[1]=mp[b]
cut[2]=mp[c]
cut[3]=mp[d]
cut[4]=mp[e]
for i in range(5):
vis[i]=0
vis[0]=1
dfs(0)
length=0
for i in range(5):
if vis[i]==1:
length+=1
if length==5:
tot+=1
print(tot)
BFS判断连通块
from queue import *
mp=[1,2,3,4,6,7,8,9,11,12,13,14]
#用来记录总共可
tot=0
#往上下左右走
d=[-1,1,-5,5]
def bfs():
vis=[0]*5#标记数组
p=0
q=Queue()
q.put(0)
vis[0]=1
while not q.empty():
i=q.get()
p+=1
for j in range(5):
if vis[j]==0:
for k in range(4):
if mp[i]+d[k]==mp[j]:
q.put(j)
vis[j]=1
if p==5:
return True
else:
return False
def perm(st,ed):
global tot
if st==5:
if bfs():
tot+=1
else:
for i in range(st,ed+1):#注意这里是ed+1
mp[st],mp[i]=mp[i],mp[st]
perm(st+1,ed)
mp[st],mp[i]=mp[i],mp[st]
perm(0,11)
print(tot//120)
用并查集判断连通块
mp=[1,2,3,4,6,7,8,9,11,12,13,14]
num=0
d=[1,-1,5,-5]
def check():
#初始化并查集,把5个数初始化为5个集
#集等于不同的数字,表示不连通
set=[0,1,2,3,4]
for i in range(5):
for j in range(5):
for k in range(4):
if mp[i]+d[k]==mp[j]:
j_set=set[j]
#把ij连通
set[j]=set[i]
for v in range(5):
if set[v]==j_set:
#和j连通的v和i也连通
set[v]=set[i]
#交错对比第一个元素和第二个元素,第二个元素和第三个元素……是否相等
if set[1:]==set[:-1]:
return True
def perm(st,ed):
global num
if st==5:
if check():
num+=1
else:
for i in range(st,ed):
mp[i],mp[st]=mp[st],mp[i]
perm(st+1,ed)
mp[i],mp[st]=mp[st],mp[i]
perm(0,11)
print(num//120)