Shortest Path to Get All Keys

该博客介绍了一个基于网格的寻路问题,目标是在有限步数内收集所有钥匙。问题中,网格包含空地、墙、起始点、字母(表示钥匙和锁)。每个锁对应一把钥匙,且字母顺序与英语字母表一致。给出的解决方案是使用宽度优先搜索(BFS),用状态表示当前位置和已收集的钥匙,并避免走入已有锁但未拥有对应钥匙的位置。算法会记录已访问过的节点,直到找到收集所有钥匙的最短路径,若无法完成则返回-1。

You are given an m x n grid grid where:

  • '.' is an empty cell.
  • '#' is a wall.
  • '@' is the starting point.
  • Lowercase letters represent keys.
  • Uppercase letters represent locks.

You start at the starting point and one move consists of walking one space in one of the four cardinal directions. You cannot walk outside the grid, or walk into a wall.

If you walk over a key, you can pick it up and you cannot walk over a lock unless you have its corresponding key.

For some 1 <= k <= 6, there is exactly one lowercase and one uppercase letter of the first k letters of the English alphabet in the grid. This means that there is exactly one key for each lock, and one lock for each key; and also that the letters used to represent the keys and locks were chosen in the same order as the English alphabet.

Return the lowest number of moves to acquire all keys. If it is impossible, return -1.

 

Example 1:

Input: grid = ["@.a.#","###.#","b.A.B"]
Output: 8
Explanation: Note that the goal is to obtain all the keys not to open all the locks.

 思路:这题跟Shortest Path Visiting All Nodes

是一模一样的题目,就是pos会重复visit,但是每次visite的状态是不一样的,收集的key是不一样的,所以用(i, j, state)来表示visit,state是用1<< (key - 'a)来表示的,代表收集了多少个key;

class Solution {
    public int shortestPathAllKeys(String[] grid) {
        int m = grid.length;
        int n = grid[0].length();
        int finalstate = 0;
        int startX = -1; int startY = -1;
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j++) {
                char c = grid[i].charAt(j);
                if(c == '@') {
                    startX = i;
                    startY = j;
                } else if('a' <= c && c <= 'f') {
                    finalstate |= 1 << (c - 'a');
                }
            }
        }
        
        Queue<int[]> queue = new LinkedList<>();
        HashSet<String> visited = new HashSet<>();
        queue.offer(new int[] {startX, startY, 0});
        visited.add(startX + " " + startY + " " + 0);
        
        int[][] dirs = new int[][] {{0,-1},{0,1},{1,0},{-1,0}};
        
        int step = 0;
        while(!queue.isEmpty()) {
            int size = queue.size();
            for(int i = 0; i < size; i++) {
                int[] node = queue.poll();
                int x = node[0];
                int y = node[1];
                int curstate = node[2];
                if(curstate == finalstate) {
                    return step;
                }
                for(int[] dir: dirs) {
                    int nextstate = curstate;
                    int nx = x + dir[0];
                    int ny = y + dir[1];
                    if(0 <= nx && nx < m && 0 <= ny && ny < n && grid[nx].charAt(ny) != '#') {
                        char c = grid[nx].charAt(ny);
                        // collect keys;
                        if('a' <= c && c <= 'f') {
                            nextstate |= 1 << (c - 'a');
                        }
                        // if next cube is lock, but i don't have keys, i still can not go;
                        if('A' <= c && c <= 'Z' && ((nextstate >> (c - 'A')) & 1) == 0) {
                            continue;
                        }
                        if(!visited.contains(nx + " "+ ny + " " + nextstate)) {
                            visited.add(nx + " "+ ny + " " + nextstate);
                            queue.offer(new int[] {nx, ny, nextstate});
                        }
                    }
                }
            }
            step++;
        }
        return -1;
    }
}

 

import numpy as np import matplotlib.pyplot as plt import pandas as pd def calc_distance(city1, city2): return np.linalg.norm(np.array(city1) - np.array(city2)) def calc_distances(cities): n_cities = len(cities) distances = np.zeros((n_cities, n_cities)) for i in range(n_cities): for j in range(i + 1, n_cities): distances[i][j] = distances[j][i] = calc_distance(cities[i], cities[j]) return distances class AntColony: def __init__(self, distances, n_ants, n_iterations, decay, alpha=1, beta=5, rho=0.1, Q=1): self.distances = distances self.pheromone = np.ones_like(distances) / len(distances) self.n_ants = n_ants self.n_iterations = n_iterations self.decay = decay self.alpha = alpha self.beta = beta self.rho = rho self.Q = Q self.shortest_path_lengths = [] def run(self): shortest_path = None shortest_path_length = np.inf for _ in range(self.n_iterations): all_paths = self.gen_all_paths() self.spread_pheromone(all_paths) shortest_path, shortest_path_length = self.get_shortest(all_paths, shortest_path, shortest_path_length) self.pheromone *= (1 - self.rho) self.shortest_path_lengths.append(shortest_path_length) return shortest_path, shortest_path_length def spread_pheromone(self, all_paths): for path in all_paths: for move in path: self.pheromone[move] += self.Q / self.distances[move] def gen_path_dist(self, path): total = 0 for move in path: total += self.distances[move] return total def gen_all_paths(self): all_paths = [] for _ in range(self.n_ants): path = self.gen_path() all_paths.append(path) return all_paths def gen_path(self): n_cities = len(self.distances) path = [] visited = set() start = np.random.randint(n_cities) visited.add(start) prev = start for _ in range(n_cities - 1): next_city = self.pick_city(prev, visited) path.append((prev, next_city)) prev = next_city visited.add(next_city) path.append((prev, start)) return path def pick_city(self, prev, visited): pheromone = np.copy(self.pheromone[prev]) pheromone[list(visited)] = 0 row = pheromone ** self.alpha * (1.0 / (self.distances[prev] + 1e-6) ** self.beta) norm_row = row / row.sum() next_city = np.random.choice(range(len(self.distances)), 1, p=norm_row)[0] return next_city def get_shortest(self, all_paths, shortest_path, shortest_path_length): for path in all_paths: path_dist = self.gen_path_dist(path) if path_dist < shortest_path_length: shortest_path = [(int(a), int(b)) for (a, b) in path] shortest_path_length = path_dist return shortest_path, shortest_path_length # 数据加载模块 try: df = pd.read_excel("100个城市的坐标.xlsx", header=None) cities = df.iloc[:, [0, 1]].values assert cities.shape[1] == 2, "坐标数据必须包含X,Y两列" except FileNotFoundError: print("错误:Excel文件未找到,请检查以下事项:") print("1. 文件是否位于当前工作目录") print("2. 文件名是否为'100个城市的坐标.xlsx'") print("3. 文件扩展名是否正确(.xlsx)") exit() except Exception as e: print(f"数据加载失败:{str(e)}") exit() # 计算距离矩阵 distances = calc_distances(cities) # 参数设置 n_ants = 20 n_iterations = 1000 decay = 0.1 alpha = 1 beta = 2 rho = 0.1 Q = 1 # 创建并运行蚁群算法 ant_colony = AntColony(distances, n_ants, n_iterations, decay, alpha, beta, rho, Q) shortest_path, shortest_path_length = ant_colony.run() # 路径格式化函数 def format_path(path): path_order = [int(path[0][0])] + [int(move[1]) for move in path] if path_order[-1] == path_order[0]: path_order = path_order[:-1] return ','.join(map(str, path_order)) # 输出结果 print("最短路径序列:", format_path(shortest_path)) print("最短路径长度:", shortest_path_length) # 可视化设置 plt.rcParams['font.sans-serif'] = 'SimHei' plt.rcParams['axes.unicode_minus'] = False # 绘制迭代曲线 plt.figure(figsize=(10, 5)) plt.plot(range(1, n_iterations + 1), ant_colony.shortest_path_lengths) plt.xlabel('迭代次数') plt.ylabel('路径长度') plt.title('算法优化过程') plt.grid(True) plt.show() # 路径可视化函数 def plot_path(cities, path): path_order = [path[0][0]] + [move[1] for move in path] x, y = cities[path_order, 0], cities[path_order, 1] plt.figure(figsize=(12, 8)) # 绘制城市点并添加编号(从1开始) for idx, (xi, yi) in enumerate(cities): plt.scatter(xi, yi, color='red', s=6,zorder=2) plt.text(xi, yi, str(idx + 1), fontsize=8,ha='center',va='bottom', color='black',zorder=3) # 绘制路径连线 plt.rcParams['font.sans-serif'] = 'SimHei' # 设置中文显示 plt.rcParams['axes.unicode_minus'] = False plt.plot(x, y, linestyle='-', marker='o', color='blue', linewidth=1, markersize=4, zorder=1) plt.xlabel('X坐标', fontsize=12) plt.ylabel('Y坐标', fontsize=12) plt.title('TSP最优路线 城市编号(1-100)', fontsize=14) plt.grid(True, linestyle='--', alpha=0.7) plt.tight_layout() plt.show() plot_path(cities, shortest_path) 修改其中代码try: df = pd.read_excel("100个城市的坐标.xlsx", header=None) cities = df.iloc[:, [0, 1]].values assert cities.shape[1] == 2, "坐标数据必须包含X,Y两列" except FileNotFoundError: print("错误:Excel文件未找到,请检查以下事项:") print("1. 文件是否位于当前工作目录") print("2. 文件名是否为'100个城市的坐标.xlsx'") print("3. 文件扩展名是否正确(.xlsx)") exit() except Exception as e: print(f"数据加载失败:{str(e)}") exit()为读取100个城市的坐标.xlsx里面的10个工作表,用file_path = '100个城市的坐标.xlsx' # 方法1:读取所有工作表(返回字典结构) # 确保在使用前正确定义变量 sheets_data = pd.read_excel('100个城市的坐标.xlsx', sheet_name=None) # 读取所有工作表 print("包含的工作表:", list(sheets_data.keys()))方法实现,给出修改之后的完整代码能直接可执行代码程序
05-28
import json import csv from math import inf import get_allpath as method_get_all_path import sys sys.path.append('str(Path(__file__).resolve().parents[0])') def get_path(topo_path): with open(topo_path, 'r') as f: Topo = json.load(f) f.close() start = Topo['start'] end = Topo['goal'][0]['host'] nodes = Topo['hosts'] edges = Topo['edges'] pathsnum = Topo['nums'] newnodes = [] newedges = [] tempedges={} for node in nodes: newnodes.append(node['host_name']) for edge in edges: path = [edge['source'], edge['target']] newedges.append(path) return start, end, newnodes, newedges,pathsnum def get_path1(start, end, nodes, edges): edgesDict = {} Numedges = {} edgesNum = {} for edge in edges: if edgesDict.get(edge[0]) == None: edgesDict[edge[0]] = [edge[1]] else: edgesDict[edge[0]].append(edge[1]) edgesDict[end] = [] myPath = method_get_all_path.GetPath(nodes, edgesDict, start, end) Path = myPath.getPath() # 存放全部攻击路径 edgePath = myPath.tran(Path) return edgePath def all_paths_conversion(all_paths, topo_path, start): path_id = [] # 每条边用编号代替 path_node = [] # 记录攻击路径上的点 with open(topo_path, 'r') as f: Topo = json.load(f) f.close() edge_ID_dict = {} for edge in Topo['edges']: dict = {edge['source'] + ',' + edge['target']: edge['edge_name']} edge_ID_dict.update(dict) # print(edge_ID_dict) for path in all_paths: temp_id = [] temp_path = [start] for source, target in path: temp_id.append(edge_ID_dict[source + ',' + target]) temp_path.append(target) path_id.append(temp_id) path_node.append(temp_path) return path_id, path_node inf_value = 1000 # 统计通过每条边的攻击路径数量 def cal_AttackPath_Count(path_id, num): APC = [0] * num # 一共20条边,初始化为0 for path in path_id: for edge in path: #print(edge) APC[int(edge[1:])-1] += 1 #print(APC) return APC # 统计通过每条边的最短路径长度 def cal_Shortest_AP_Length(path_id, num): Shortest_len = [inf_value] * num for path in path_id: for edge in path: Shortest_len[int(edge[1:])-1] = min(Shortest_len[int(edge[1:])-1], len(path) + 1) # print('shortest', Shortest_len) return Shortest_len # 统计通过每条边的攻击路径长度的均值 def cal_AttackPath_Length_Average(path_id, num): AP_length = [0] * num AP_cnt = [0] * num for path in path_id: for edge in path: AP_length[int(edge[1:])-1] += len(path) + 1 AP_cnt[int(edge[1:])-1] += 1 AP_length_aver = [0] * num for i in range(len(AP_length)): if AP_cnt[i] != 0: AP_length_aver[i] = AP_length[i] / AP_cnt[i] else: AP_length_aver[i] = 0 # print(AP_length) # print(AP_cnt) # print(AP_length_aver) # new_c3 = [1/t for t in AP_length_aver] # return new_c3 return AP_length_aver # 统计漏洞距离攻击起点的最短距离 def cal_shortest_distance_to_S0(path_id, num): shortest_dis = [inf_value] * num for path in path_id: for dis, edge in enumerate(path): shortest_dis[int(edge[1:])-1] = min(shortest_dis[int(edge[1:])-1], dis + 1) print(shortest_dis) end_dis = [8-t for t in shortest_dis] return end_dis # return shortest_dis # 计算CC,计算边到其他节点最短距离和的倒数 def cal_cc(path, topo_path): with open(topo_path, 'r') as f: edge_ID_dict = json.load(f) f.close() node_num = 11 node_dis = [[inf_value] * node_num for _ in range(node_num)] for te in path: for i in range(len(te)-1): for j in range(i+1,len(te)): if te[j] == 'T': node_i, node_j = int(te[i][1:]), node_num - 1 else: node_i, node_j = int(te[i][1:]), int(te[j][1:]) # print(node_i, node_j) node_dis[node_i][node_j] = min(node_dis[node_i][node_j], j-i) # print('=====') CC_node = [0] * node_num for i in range(len(node_dis)): for j in range(len(node_dis[i])): if node_dis[i][j] != inf_value: CC_node[i] += node_dis[i][j] CC_edge = [0] * 20 for key in edge_ID_dict.keys(): CC_edge[int(edge_ID_dict[key][1:]) - 1] = CC_node[int(key.split(',')[0][1:])] # print(CC_edge) for i,num in enumerate(CC_edge): if CC_edge[i] == 0: CC_edge[i] = 0 else: CC_edge[i] = (node_num-1) / CC_edge[i] # print(CC_edge) # for k in CC_edge: # print(k) return CC_edge # 计算残余中心性 # 计算删除某条边后的残余中心性 def cal_RCC(path, nodenum, edgenum, topo_path): # for t in range(len(path)): # print(path[t]) # print('-=-==-=-==-=') # print(edge_ID_dict) with open(topo_path, 'r') as f: Topo = json.load(f) f.close() edge_ID_dict = {} for edge in Topo['edges']: dict = {edge['source'] + ',' + edge['target']: edge['edge_name']} edge_ID_dict.update(dict) RCC = [0] * edgenum node_num = nodenum + 1 for i in range(len(RCC)): delete_edge = 'E'+str(i+1) # 删除的边为E(i+2) for key in edge_ID_dict.keys(): if edge_ID_dict[key] == delete_edge: source = key.split(',')[0] target = key.split(',')[1] break after_delete_paths = [] # 删除了某条边剩余的攻击路径 for each_path in path: # print(each_path) flag = 1 for q in range(len(each_path)-1): # print(each_path[q], each_path[q + 1]) if each_path[q] == source and each_path[q+1] == target: flag = -1 # print(1) break if flag == 1: after_delete_paths.append(each_path) # print(after_delete_paths) node_dis = [[inf] * node_num for _ in range(node_num)] # 记录节点到其他节点的最短距离 # print(after_delete_paths) for temp_path in after_delete_paths: # print(temp_path) for u in range(len(temp_path)-1): # print("u ", temp_path[u]) for v in range(u+1,len(temp_path)): if temp_path[v] == 'T': node_dis[int(temp_path[u][1:])][-1] = min(v-u, node_dis[int(temp_path[u][1:])][-1]) else: node_dis[int(temp_path[u][1:])][int(temp_path[v][1:])] = min(v-u, node_dis[int(temp_path[u][1:])][int(temp_path[v][1:])]) # print(int(temp_path[v][1:]), node_dis[int(temp_path[u][1:])][int(temp_path[v][1:])]) # print(node_dis[int(temp_path[u][1:])], "\n") res = 0 for x in range(len(node_dis)): for y in range(len(node_dis[0])): res += 1/node_dis[x][y] # print("res", res) # for k in node_dis: # print(k) # print(delete_edge, len(after_delete_paths),res) # for k in after_delete_paths: # print(k) # print('=====================') # break RCC[i] = res # print(RCC) return RCC def cal_path_metrics(topo_path, AttackPath_Count, Shortest_AP_Length, AttackPath_Length_Average, shortest_distance_to_S0, output_path): with open(topo_path, 'r') as f: edges = json.load(f)['edges'] f.close() path_metrics = [['边', '攻击路径数量', '最短路径长度', '攻击路径长度的均值', '距离攻击起点的最短距离']] # print(AttackPath_Count) for edge in edges: name = edge['edge_name'] no = int(name[1:])-1 ac = AttackPath_Count[no] # print(no, ac) sal = Shortest_AP_Length[no] ala = AttackPath_Length_Average[no] sdt0 = shortest_distance_to_S0[no] # cc = CC[no] path_metrics.append([name, ac, sal, ala, sdt0]) # print(path_metrics) with open(output_path, 'w', newline='') as file: writer = csv.writer(file) writer.writerows(path_metrics) if __name__ == '__main__': topo_path = sys.argv[1]; metrics_path = sys.argv[2] start, end, nodes, edges, nums = get_path(topo_path) all_paths = get_path1(start, end, nodes, edges) # all_paths 记录了攻击路径 path_id, path_node = all_paths_conversion(all_paths, topo_path, start) m1 = cal_AttackPath_Count(path_id, nums[2]) m2 = cal_Shortest_AP_Length(path_id, nums[2]) m3 = cal_AttackPath_Length_Average(path_id, nums[2]) m4 = cal_shortest_distance_to_S0(path_id, nums[2]) # m10 = cal_RCC(path_node, nums[1], nums[2], topo_path) cal_path_metrics(topo_path, m1, m2, m3, m4, metrics_path) 分析整体代码的功能,需要的输入和输出来源,无需修改代码
08-06
import json import csv from math import inf import sys from pathlib import Path sys.path.append(str(Path(file).resolve().parents[0])) import get_allpath as method_get_all_path def get_path(topo_path): with open(topo_path, ‘r’) as f: Topo = json.load(f) f.close() start = Topo[‘start’] end = Topo[‘goal’][0][‘host’] nodes = Topo[‘hosts’] edges = Topo[‘edges’] pathsnum = Topo[‘nums’] newnodes = [] newedges = [] tempedges={} for node in nodes: newnodes.append(node['host_name']) for edge in edges: path = [edge['source'], edge['target']] newedges.append(path) return start, end, newnodes, newedges,pathsnum def get_path1(start, end, nodes, edges): edgesDict = {} Numedges = {} edgesNum = {} for edge in edges: if edgesDict.get(edge[0]) == None: edgesDict[edge[0]] = [edge[1]] else: edgesDict[edge[0]].append(edge[1]) edgesDict[end] = [] # print(nodes) # print(edgesDict[end]) myPath = method_get_all_path.GetPath(nodes, edgesDict, start, end) Path = myPath.getPath() # 存放全部攻击路径 edgePath = myPath.tran(Path) return edgePath def all_paths_conversion(all_paths, topo_path, start): path_id = [] # 每条边用编号代替 path_node = [] # 记录攻击路径上的点 with open(topo_path, 'r') as f: Topo = json.load(f) f.close() edge_ID_dict = {} for edge in Topo['edges']: dict = {edge['source'] + ',' + edge['target']: edge['edge_name']} edge_ID_dict.update(dict) # print(edge_ID_dict) for path in all_paths: temp_id = [] temp_path = [start] for source, target in path: temp_id.append(edge_ID_dict[source + ',' + target]) temp_path.append(target) path_id.append(temp_id) path_node.append(temp_path) return path_id, path_node inf_value = 1000 统计通过每条边的攻击路径数量 def cal_AttackPath_Count(path_id, num): APC = [0] * num # 一共20条边,初始化为0 for path in path_id: for edge in path: #print(edge) APC[int(edge[1:])-1] += 1 #print(APC) return APC 统计通过每条边的最短路径长度 def cal_Shortest_AP_Length(path_id, num): Shortest_len = [inf_value] * num for path in path_id: for edge in path: Shortest_len[int(edge[1:])-1] = min(Shortest_len[int(edge[1:])-1], len(path) + 1) # print(‘shortest’, Shortest_len) return Shortest_len 统计通过每条边的攻击路径长度的均值 def cal_AttackPath_Length_Average(path_id, num): AP_length = [0] * num AP_cnt = [0] * num for path in path_id: for edge in path: AP_length[int(edge[1:])-1] += len(path) + 1 AP_cnt[int(edge[1:])-1] += 1 AP_length_aver = [0] * num for i in range(len(AP_length)): if AP_cnt[i] != 0: AP_length_aver[i] = AP_length[i] / AP_cnt[i] else: AP_length_aver[i] = 0 # print(AP_length) # print(AP_cnt) # print(AP_length_aver) # new_c3 = [1/t for t in AP_length_aver] # return new_c3 return AP_length_aver 统计漏洞距离攻击起点的最短距离 def cal_shortest_distance_to_S0(path_id, num): shortest_dis = [inf_value] * num for path in path_id: for dis, edge in enumerate(path): shortest_dis[int(edge[1:])-1] = min(shortest_dis[int(edge[1:])-1], dis + 1) # print(shortest_dis) # end_dis = [8-t for t in shortest_dis] # return end_dis return shortest_dis 计算CC,计算边到其他节点最短距离和的倒数 def cal_cc(path, topo_path): with open(topo_path, ‘r’) as f: edge_ID_dict = json.load(f) f.close() node_num = 11 node_dis = [[inf_value] * node_num for _ in range(node_num)] for te in path: for i in range(len(te)-1): for j in range(i+1,len(te)): if te[j] == 'T': node_i, node_j = int(te[i][1:]), node_num - 1 else: node_i, node_j = int(te[i][1:]), int(te[j][1:]) # print(node_i, node_j) node_dis[node_i][node_j] = min(node_dis[node_i][node_j], j-i) # print('=====') CC_node = [0] * node_num for i in range(len(node_dis)): for j in range(len(node_dis[i])): if node_dis[i][j] != inf_value: CC_node[i] += node_dis[i][j] CC_edge = [0] * 20 for key in edge_ID_dict.keys(): CC_edge[int(edge_ID_dict[key][1:]) - 1] = CC_node[int(key.split(',')[0][1:])] # print(CC_edge) for i,num in enumerate(CC_edge): if CC_edge[i] == 0: CC_edge[i] = 0 else: CC_edge[i] = (node_num-1) / CC_edge[i] # print(CC_edge) # for k in CC_edge: # print(k) return CC_edge 计算残余中心性 计算删除某条边后的残余中心性 def cal_RCC(path, nodenum, edgenum, topo_path): # for t in range(len(path)): # print(path[t]) # print(‘-=--=--=’) # print(edge_ID_dict) with open(topo_path, ‘r’) as f: Topo = json.load(f) f.close() edge_ID_dict = {} for edge in Topo[‘edges’]: dict = {edge[‘source’] + ‘,’ + edge[‘target’]: edge[‘edge_name’]} edge_ID_dict.update(dict) RCC = [0] * edgenum node_num = nodenum + 1 for i in range(len(RCC)): delete_edge = ‘E’+str(i+1) # 删除的边为E(i+2) for key in edge_ID_dict.keys(): if edge_ID_dict[key] == delete_edge: source = key.split(‘,’)[0] target = key.split(‘,’)[1] break after_delete_paths = [] # 删除了某条边剩余的攻击路径 for each_path in path: # print(each_path) flag = 1 for q in range(len(each_path)-1): # print(each_path[q], each_path[q + 1]) if each_path[q] == source and each_path[q+1] == target: flag = -1 # print(1) break if flag == 1: after_delete_paths.append(each_path) # print(after_delete_paths) node_dis = [[inf] * node_num for _ in range(node_num)] # 记录节点到其他节点的最短距离 # print(after_delete_paths) for temp_path in after_delete_paths: # print(temp_path) for u in range(len(temp_path)-1): # print("u ", temp_path[u]) for v in range(u+1,len(temp_path)): if temp_path[v] == ‘T’: node_dis[int(temp_path[u][1:])][-1] = min(v-u, node_dis[int(temp_path[u][1:])][-1]) else: node_dis[int(temp_path[u][1:])][int(temp_path[v][1:])] = min(v-u, node_dis[int(temp_path[u][1:])][int(temp_path[v][1:])]) # print(int(temp_path[v][1:]), node_dis[int(temp_path[u][1:])][int(temp_path[v][1:])]) # print(node_dis[int(temp_path[u][1:])], “\n”) res = 0 for x in range(len(node_dis)): for y in range(len(node_dis[0])): res += 1/node_dis[x][y] # print("res", res) # for k in node_dis: # print(k) # print(delete_edge, len(after_delete_paths),res) # for k in after_delete_paths: # print(k) # print('=====================') # break RCC[i] = res # print(RCC) return RCC def cal_path_metrics(topo_path, AttackPath_Count, Shortest_AP_Length, AttackPath_Length_Average, shortest_distance_to_S0, output_path): with open(topo_path, ‘r’) as f: edges = json.load(f)[‘edges’] f.close() path_metrics = [[‘边’, ‘攻击路径数量’, ‘最短路径长度’, ‘攻击路径长度的均值’, ‘距离攻击起点的最短距离’]] # print(AttackPath_Count) for edge in edges: name = edge[‘edge_name’] no = int(name[1:])-1 ac = AttackPath_Count[no] # print(no, ac) sal = Shortest_AP_Length[no] ala = AttackPath_Length_Average[no] sdt0 = shortest_distance_to_S0[no] # cc = CC[no] path_metrics.append([name, ac, sal, ala, sdt0]) # print(path_metrics) with open(output_path, ‘w’, newline=‘’) as file: writer = csv.writer(file) writer.writerows(path_metrics) if name == ‘main’: topo_path = sys.argv[1]; metrics_path = sys.argv[2] start, end, nodes, edges, nums = get_path(topo_path) all_paths = get_path1(start, end, nodes, edges) # all_paths 记录了攻击路径 path_id, path_node = all_paths_conversion(all_paths, topo_path, start) m1 = cal_AttackPath_Count(path_id, nums[2]) m2 = cal_Shortest_AP_Length(path_id, nums[2]) m3 = cal_AttackPath_Length_Average(path_id, nums[2]) m4 = cal_shortest_distance_to_S0(path_id, nums[2]) # m10 = cal_RCC(path_node, nums[1], nums[2], topo_path) cal_path_metrics(topo_path, m1, m2, m3, m4, metrics_path)分析这段代码额功能,所需要的输入和输出,分别从哪个路径下的文件里获取,无需修改代码
最新发布
08-06
import numpy as np import random # 定义罗马尼亚地图的距离矩阵 def create_distance_matrix(): cities = ['Arad', 'Bucharest', 'Craiova', 'Drobeta', 'Eforie', 'Fagaras', 'Giurgiu', 'Hirsova', 'Iasi', 'Lugoj', 'Mehadia', 'Neamt', 'Oradea', 'Pitesti', 'Rimnicu Vilcea', 'Sibiu', 'Timisoara', 'Urziceni', 'Vaslui', 'Zerind'] distances = { ('Arad', 'Zerind'): 75, ('Arad', 'Timisoara'): 118, ('Arad', 'Sibiu'): 140, ('Zerind', 'Oradea'): 71, ('Oradea', 'Sibiu'): 151, ('Timisoara', 'Lugoj'): 111, ('Lugoj', 'Mehadia'): 70, ('Mehadia', 'Drobeta'): 75, ('Drobeta', 'Craiova'): 120, ('Craiova', 'Rimnicu Vilcea'): 146, ('Craiova', 'Pitesti'): 138, ('Sibiu', 'Fagaras'): 99, ('Sibiu', 'Rimnicu Vilcea'): 80, ('Fagaras', 'Bucharest'): 211, ('Rimnicu Vilcea', 'Pitesti'): 97, ('Pitesti', 'Bucharest'): 101, ('Giurgiu', 'Bucharest'): 90, ('Urziceni', 'Bucharest'): 85, ('Urziceni', 'Hirsova'): 98, ('Urziceni', 'Vaslui'): 142, ('Hirsova', 'Eforie'): 86, ('Vaslui', 'Iasi'): 92, ('Iasi', 'Neamt'): 87 } # 创建距离矩阵 n_cities = len(cities) distance_matrix = np.full((n_cities, n_cities), np.inf) city_index = {city: i for i, city in enumerate(cities)} for (city1, city2), dist in distances.items(): distance_matrix[city_index[city1], city_index[city2]] = dist distance_matrix[city_index[city2], city_index[city1]] = dist # 设置对角线为无穷大,避免自环 np.fill_diagonal(distance_matrix, np.inf) return cities, distance_matrix, city_index # 蚁群算法 class AntColony: def __init__(self, distances, n_ants, n_best, n_iterations, decay, alpha=1, beta=1): self.distances = distances self.pheromone = np.ones(self.distances.shape) / len(distances) self.all_inds = range(len(distances)) self.n_ants = n_ants self.n_best = n_best self.n_iterations = n_iterations self.decay = decay self.alpha = alpha self.beta = beta def run(self): shortest_path = None all_time_shortest_path = ("placeholder", np.inf) for i in range(self.n_iterations): all_paths = self.gen_all_paths() self.spread_pheronome(all_paths, self.n_best) shortest_path = min(all_paths, key=lambda x: x[1]) if shortest_path[1] < all_time_shortest_path[1]: all_time_shortest_path = shortest_path self.pheromone *= self.decay # 防止信息素过低 self.pheromone[self.pheromone < 1e-10] = 1e-10 return all_time_shortest_path def gen_all_paths(self): all_paths = [] for i in range(self.n_ants): path = self.gen_path(0) # 假设从第一个城市出发 all_paths.append((path, self.get_cost(path))) return all_paths def gen_path(self, start): path = [] visited = set() visited.add(start) prev = start for i in range(len(self.distances) - 1): move = self.pick_move(self.pheromone[prev], self.distances[prev], visited) if move is None: # 如果无法移动,尝试寻找任意可达的城市 possible_moves = [city for city in self.all_inds if city not in visited and self.distances[prev, city] < np.inf] if not possible_moves: # 如果没有可达的城市,提前结束路径 break move = random.choice(possible_moves) path.append((prev, move)) prev = move visited.add(move) # 尝试回到起点 if prev != start and self.distances[prev, start] < np.inf: path.append((prev, start)) else: # 如果无法直接回到起点,寻找一个可以回到起点的中间城市 possible_moves = [city for city in visited if self.distances[prev, city] < np.inf and self.distances[city, start] < np.inf] if possible_moves: mid_city = possible_moves[0] path.append((prev, mid_city)) path.append((mid_city, start)) else: # 如果还是无法回到起点,随机选择一个可达的城市 possible_moves = [city for city in self.all_inds if city not in visited and self.distances[prev, city] < np.inf] if possible_moves: mid_city = random.choice(possible_moves) path.append((prev, mid_city)) # 再尝试从这个城市回到起点 if self.distances[mid_city, start] < np.inf: path.append((mid_city, start)) return path def pick_move(self, pheromone, dist, visited): # 复制信息素数组并将已访问城市的信息素设为0 pheromone = np.copy(pheromone) pheromone[list(visited)] = 0 # 处理距离为无穷大的情况 with np.errstate(divide='ignore'): # 计算转移概率 row = pheromone ** self.alpha * ((1.0 / dist) ** self.beta) # 检查是否所有可能的移动都是无效的 if np.all(row == 0): # 如果没有有效移动,返回None return None # 归一化概率分布 norm_row = row / row.sum() # 处理数值稳定性问题 if np.isnan(norm_row).any(): # 如果存在NaN,尝试修复 valid_indices = np.where(np.isfinite(norm_row))[0] if len(valid_indices) > 0: # 只从有效索引中选择 valid_probs = norm_row[valid_indices] valid_probs /= valid_probs.sum() move_index = np.random.choice(valid_indices, p=valid_probs) return move_index else: return None # 正常选择移动 move = np.random.choice(self.all_inds, 1, p=norm_row)[0] return move def spread_pheronome(self, all_paths, n_best): sorted_paths = sorted(all_paths, key=lambda x: x[1]) for path, dist in sorted_paths[:n_best]: for move in path: # 确保移动是有效的元组 if isinstance(move, tuple) and len(move) == 2: self.pheromone[move] += 1.0 / self.distances[move] def get_cost(self, path): total_cost = 0 for move in path: # 确保移动是有效的元组 if isinstance(move, tuple) and len(move) == 2: total_cost += self.distances[move] return total_cost # 主函数 if __name__ == "__main__": cities, distance_matrix, city_index = create_distance_matrix() ant_colony = AntColony(distance_matrix, n_ants=20, n_best=5, n_iterations=100, decay=0.95) shortest_path = ant_colony.run() # 打印更友好的结果 path_indices, total_distance = shortest_path city_names = list(city_index.keys()) path_cities = [] for move in path_indices: if isinstance(move, tuple) and len(move) == 2: path_cities.append(f"{city_names[move[0]]} -> {city_names[move[1]]}") print(f"最短路径总距离: {total_distance}") print("路径详情:") for step in path_cities: print(step)(1)题目描述 (2)算法思想 (3)软件说明 (4)关键代码 (5)运行结果及分析 按照这个写一下代码的报告
06-21
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值