相关链接
783. 最小危险值路径
数据结构–最小生成树详解
最短路径算法之 Floyd
在线测试
1. 点击右边的测试数据按钮,可以切换数据
2. 点击右边的最小生成树,可以切换是否开启这功能
3. 点击右边的操作模式
* 拖动节点: 可以拖动节点,默认都可以
* 设置起始点: 选中该模式,再点击节点,可以将该节点设置为最短寻路起始点。节点下标Start
* 设置结束点: 选中该模式,再点击节点,可以将该节点设置为最短寻结束点。节点下标End
寻得的路线为绿色连线,红色表示该路线中成本最大的值
4. 修改数据
(1) 先点击“导出数据按钮”,会在页面下方输出图形json数据
(2) 编辑数据,点提交就可以修改了。只需要修改属性 x(起点), y(目标点), w(成本)
Prim.ts
namespace ihaiu { /** 作为记录边的信息,这些边都是达到end的所有边中,权重最小的那个 */ export class PrimAssis { // 边的终点 start: number = 0; // 边的起点 end: number = 0; // 边的权重 weight: number = 0; } /** 最小生成树之Prim普里姆算法 */ export class Prim { // 成本矩阵 arcs: number[][]; // 计算结果 result: GraphData; constructor() { } /** 获取路径成本 */ public getArcs(from: number, to: number): number { return this.arcs[from][to]; } /** 是否有连接线 */ public hasEdge(from: number, to: number): boolean { let arc = this.getArcs(from, to); return arc != Number.MAX_VALUE && arc != 0; } public calculationByGraphData(g: GraphData, beginIndex: number = 0):GraphData { g.check(); let g2 = this.calculation( g.nodeNum, g.edegeNum, g.x, g.y, g.w, beginIndex ); g2.nodeNum = g.nodeNum; g2.nodes = g.nodes; return g2; } /** 计算寻路 */ public calculation(nodeNum: number, edegeNum: number, x: number[], y: number[], w: number[], beginIndex: number = 0):GraphData { // 结果图 let result: GraphData = new GraphData().init(); // 成本矩阵 let arcs: number[][] = []; // 初始化矩阵值 for(let u = 0; u < nodeNum; u ++) { arcs[u] = []; for(let v = 0; v < nodeNum; v ++) { arcs[u][v] = Number.MAX_VALUE; } } // 输入边 for(let i = 0; i < x.length; i ++) { let u = x[i]; let v = y[i]; arcs[u][v] = w[i]; arcs[v][u] = w[i]; } //closeEdge这个数组记录到达某个顶点的各个边中的权重最大的那个边 let closeEdges: PrimAssis[] = []; for(let i = 0; i < nodeNum; i ++) { closeEdges.push(new PrimAssis()); } //进行closeEdge的初始化,更加开始起点进行初始化 for(let i = 0; i < nodeNum; i ++) { if(i != beginIndex) { let edge = closeEdges[i]; edge.start = beginIndex; edge.end = i; edge.weight = arcs[beginIndex][i]; } } //把起点的closeEdge中的值设置为-1,代表已经加入到集合U了 closeEdges[beginIndex].weight = -1; //访问剩下的顶点,并加入依次加入到集合U for(let i = 1; i< nodeNum; i ++) { let minWeight = Number.MAX_VALUE; let minIndex = 0; //寻找数组close_edge中权重最小的那个边 for(let k = 0; k < nodeNum; k ++) { if(closeEdges[k].weight != -1) { if(closeEdges[k].weight < minWeight) { minWeight = closeEdges[k].weight; minIndex = k; } } } let minEdge = closeEdges[minIndex]; //将权重最小的那条边的终点也加入到集合U minEdge.weight = -1; //输出对应的边的信息 result.addEdge( minEdge.start, minEdge.end, arcs[minEdge.start][minEdge.end] ); //更新我们的close_edge数组。 for (let k = 0; k < nodeNum; k++) { let edge = closeEdges[k]; if (arcs[minEdge.end][k] < edge.weight) { edge.weight = arcs[minEdge.end][k]; edge.start = minEdge.end; edge.end = k; } } } this.arcs = arcs; this.result = result; return result; } } }
GraphData.ts
namespace ihaiu { /** * 图形数据 */ export class GraphData { // 边--from x: number[]; // 边--to y: number[]; // 边--危险值 w: number[]; // 节点数量 nodeNum = 0; // 边数 edegeNum = 0; // 节点 nodes: Node[] = []; public init(): GraphData { this.x = []; this.y = []; this.w = []; return this; } // 添加边 public addEdge(x: number, y:number, w: number): GraphData { this.x.push(x); this.y.push(y); this.w.push(w); return this; } public check() { this.checkNodeNum(); this.edegeNum = this.x.length; if(this.nodes != null && this.nodes.length >= this.nodeNum) { return; } let list: Node[] = []; for(let i = 0; i < this.nodeNum; i ++) { let node : Node; if(i < this.nodes.length ) { node = this.nodes[i]; } else { node = new Node(); node.pos.x = Math.floor( Math.random() * 200 + 50 ) ; node.pos.y = Math.floor( Math.random() * 200 + 50 ); } node.index = i; list.push(node); } this.nodes = list; } // 矫正顶点数量 public checkNodeNum() { let x = this.x; let y = this.y; let num = 0; for(let i = 0; i < x.length; i ++) { num = Math.max(x[i], num); num = Math.max(y[i], num); } this.nodeNum = Math.max(num + 1, this.nodeNum); } static parse(json:string) { let g = new GraphData(); try { let o = JSON.parse(json); g.edegeNum = o.edegeNum; g.nodeNum = o.nodeNum; g.x = o.x; g.y = o.y; g.w = o.w; let list: Node[] = []; for(let i = 0; i < o.nodes.length; i ++) { let item = o.nodes[i]; let node : Node = new Node(); node.index = item.index; node.pos.x = item.pos.x; node.pos.y = item.pos.y; list.push(node); } g.nodes = list; } catch (error) { alert("解析json数据错误:" + error); } return g; } } }
Node.ts
namespace ihaiu { export class NodeState { static Normal = 0; static Disable = 1; static Start = 2; static End = 3; static Greend = 4; } export class LineState { static Normal = 0; static Disable = 1; static Green = 2; static GreenMax = 3; } /** * 节点 */ export class Node { // 节点索引 index: number; // 坐标 pos: Point = new Point(); // 子节点 // childes: Node[] = []; } }
Point.ts
namespace ihaiu { /** * 路径点 */ export class Point { x: number = 0; y: number = 0; /** 获取到目标点距离 */ public getDistance(to: Point): number { let dx = to.x - this.x; let dy = to.y - this.y; return Math.sqrt(dx * dx + dy * dy); } /** 获取到目标点弧度 */ public getRadian(to: Point) : number { let dx = to.x - this.x; let dy = to.y - this.y; return Math.atan2(dy, dx); } /** 获取到目标点角度 */ public getAngle(to: Point) : number { return this.getRadian(to) * 180 / Math.PI ; } /** 获取中心点 */ public static center(a: Point, b: Point): Point { let p = new Point(); p.x = a.x + (b.x - a.x) * 0.5; p.y = a.y + (b.y - a.y) * 0.5; return p; } /** 获取相对A中心点 */ public static centerRelative(a: Point, b: Point): Point { let p = new Point(); p.x = (b.x - a.x) * 0.5; p.y = (b.y - a.y) * 0.5; return p; } } }