# 读取CSV文件创建字典表示关系图 def load(self): with open(self.input_file, 'r') as f_in: lines = list(csv.reader(f_in)) self.A_num = len(lines) # A部落人数 self.B_num = len(lines[0]) # B部落人数 for m in range(self.A_num + self.B_num): self.graphAB[m] = deque([]) for i in range(self.A_num): for j in range(self.B_num): if lines[i][j] == '1': # A的id:0 ~ self.A_num - 1 # B的id:self.A_num ~ self.A_num + self.B_num - 1 self.graphAB[i].append(j + self.A_num) self.graphAB[j + self.A_num].append(i)
# 深度优先遍历搜索小于等于8的路径 def DFS(self, s,A_head,path): """ 根据好友关系搜索环,直到深度小于8或没有为止 并根据对应关系存入4,6,8的环和6,7,8的单链 s: 搜索起始点 A_head: 最开始的起点A path: 搜索出的路径 """ # 计算路径的长度 path_len = len(path) # 4,6,8的路径的下一个朋友是起点,成4,6,8的环 if (path_len > 2) and (A_head in self.graphAB[s]) : path_ = path[1:] #深拷贝当前path,丢掉开头 path_.sort() #升序排列 # 进行字符串编码 path_s = ''.join(p for p in map(str, path_)) # 利用set()和内置hash函数去重 if path_s not in self.circles[path_len]: self.circles[path_len].add(path_s) self.count[path_len] += 1 # 6,7,8的路径塞进存储中,后续组合配对成环 if (path_len > 5) and (path_len < 9): self.lines[path_len].append(path[1:])
# 深度优先搜索,长度只搜到8 if path_len < 8: for f_next in self.graphAB[s]: # 如果一个一个搜,可以这样写,每个环只往下搜避免重复 # if (f_next not in path) and (f_next > A_head): if (f_next not in path): path.append(f_next) self.DFS(f_next, A_head, path) path.pop()
#将找到固定长度的单链两两组合成环并去重 def lines2circles(self): """ 把以某个A为起点搜索出的固定长度的单链进行比较 找出除起终点相同任意元素都不同的单链两两配对成环 lines: 指定长度的单链集合列表,每个单链开头的元素相同,都是以A中某人为起点 """ # 依次拼接长度为6,7,8的单链 # 初始化访问标志位,便于确立是否可以拼接两条单链 visited = [0] * (self.A_num + self.B_num) for k,v in zip(self.lines.keys(),self.lines.values()): len_lines = len(v) #单链的数量 # 以某个A为起点的固定长度单链可能没有或只有一个, # 这个时候无法成环,不用继续运行 if (len_lines == 0) or (len_lines == 1): return # 开始找环 len_circle = 2 * k - 2 # 将lines按照最后一个元素进行升序,降低循环次数 v = sorted(v,key=lambda k:k[-1])
for t in range(len_lines - 1): line1 = v[t] for s in line1: visited[s] = 1 for k in range(t+1, len_lines): #确保只在起终点相同的line中组合,第二个没有后面一定没有 if line1[-1] != v[k][-1]: break #找出两个中相同的元素 line2 = v[k][:-1] SAME = 0 # 合并双链判断标志 # 除了开头和末尾还有其他元素相同,无法配对成环 for s in line2: if visited[s] == 1: SAME = 1 break if SAME == 0: #去掉相同的头和尾元素,成环并升序 circle = line1 + line2 circle.sort() # 字符串编码环存入set() circle_ = ''.join(c for c in map(str, circle)) if circle_ not in self.circles[len_circle]: self.circles[len_circle].add(circle_) self.count[len_circle] += 1 for s in line1: visited[s] = 0