当前位置: 首页 > wzjs >正文

网站建设丨找王科杰专业网络广告一般是怎么收费

网站建设丨找王科杰专业,网络广告一般是怎么收费,淘宝客建站教程,武汉网站制作 费用Dijkstra算法 前言概念BFS基础模版DijkstraDijkstra函数签名State类distTo 记录最短路径伪代码模版第一个问题解答第二个问题解答第三个问题解答 前言 学习这个算法之间,必须要对BFS遍历比较熟悉,它的本质就是一个特殊改造过的BFS算法. 概念 Dijkstra算法是一种计算图中单源…

Dijkstra算法

    • 前言
    • 概念
    • BFS基础模版
    • Dijkstra
      • Dijkstra函数签名
      • State类
      • distTo 记录最短路径
      • 伪代码模版
        • 第一个问题解答
        • 第二个问题解答
        • 第三个问题解答

前言

学习这个算法之间,必须要对BFS遍历比较熟悉,它的本质就是一个特殊改造过的BFS算法.

概念

Dijkstra算法是一种计算图中单源最短路径算法,本质上是一个经过特殊改造的BFS算法,改造点有两个:

  • 使用优先队列,而不是普通队列进行BFS算法.
  • 添加了一个备忘录,记录起点到每个可达节点的最短路径权重和.

BFS基础模版

// 图结构的 BFS 遍历,从节点 s 开始进行 BFS,且记录路径的权重和
// 每个节点自行维护 State 类,记录从 s 走来的权重和
class State {// 当前节点 IDint node;// 从起点 s 到当前节点的权重和int weight;public State(int node, int weight) {this.node = node;this.weight = weight;}
}void bfs(Graph graph, int s) {boolean[] visited = new boolean[graph.size()];Queue<State> q = new LinkedList<>();q.offer(new State(s, 0));visited[s] = true;while (!q.isEmpty()) {State state = q.poll();int cur = state.node;int weight = state.weight;System.out.println("visit " + cur + " with path weight " + weight);for (Edge e : graph.neighbors(cur)) {if (!visited[e.to]) {q.offer(new State(e.to, weight + e.weight));visited[e.to] = true;}}}
}

Dijkstra

Dijkstra函数签名

输入是一幅图 graph 和一个起点 start,返回是一个记录最短路径权重的数组:

// 输入一幅图和一个起点 start,计算 start 到其他节点的最短距离
int[] dijkstra(int start, Graph graph);

State类

我们也需要一个 State 类来辅助 BFS 算法的运行,清晰起见,我们用 id 变量记录当前节点 ID,用 distFromStart 变量记录从起点到当前节点的距离。

class State {// 图节点的 idint id;// 从 start 节点到当前节点的距离int distFromStart;State(int id, int distFromStart) {this.id = id;this.distFromStart = distFromStart;}
}

distTo 记录最短路径

加权图中的 Dijkstra 算法和无权图中的普通 BFS 算法不同,在 Dijkstra 算法中,你第一次经过某个节点时的路径权重,不见得就是最小的,所以对于同一个节点,我们可能会经过多次,而且每次的 distFromStart 可能都不一样,比如下图:
在这里插入图片描述
当重复遍历到同一个节点时,我们可以比较一下当前的 distFromStart 和 distTo 中的值,如果当前的更小,就更新 distTo,反之,就不用再往后继续遍历了。

伪代码模版

// 输入一幅图和一个起点 start,计算 start 到其他节点的最短距离
int[] dijkstra(int start, Graph graph) {// 图中节点的个数int V = graph.size();// 记录最短路径的权重,你可以理解为 dp table// 定义:distTo[i] 的值就是节点 start 到达节点 i 的最短路径权重int[] distTo = new int[V];// 求最小值,所以 dp table 初始化为正无穷Arrays.fill(distTo, Integer.MAX_VALUE);// base case,start 到 start 的最短距离就是 0distTo[start] = 0;// 优先级队列,distFromStart 较小的排在前面Queue<State> pq = new PriorityQueue<>((a, b) -> {return a.distFromStart - b.distFromStart;});// 从起点 start 开始进行 BFSpq.offer(new State(start, 0));while (!pq.isEmpty()) {State curState = pq.poll();int curNodeID = curState.id;int curDistFromStart = curState.distFromStart;if (curDistFromStart > distTo[curNodeID]) {// 已经有一条更短的路径到达 curNode 节点了continue;}// 将 curNode 的相邻节点装入队列for (int nextNodeID : graph.neighbors(curNodeID)) {// 看看从 curNode 达到 nextNode 的距离是否会更短int distToNextNode = distTo[curNodeID] + graph.weight(curNodeID, nextNodeID);if (distTo[nextNodeID] > distToNextNode) {// 更新 dp tabledistTo[nextNodeID] = distToNextNode;// 将这个节点以及距离放入队列pq.offer(new State(nextNodeID, distToNextNode));}}}return distTo;
}

对比普通的 BFS 算法,你可能会有以下疑问:

1、没有 visited 集合记录已访问的节点,所以一个节点会被访问多次,会被多次加入队列,那会不会导致队列永远不为空,造成死循环?

2、为什么用优先级队列 PriorityQueue 而不是 LinkedList 实现的普通队列?为什么要按照 distFromStart 的值来排序?

3、如果我只想计算起点 start 到某一个终点 end 的最短路径,是否可以修改算法,提升一些效率?

第一个问题解答

循环结束的条件是队列为空,那么你就要注意看什么时候往队列里放元素(调用 offer 方法),再注意看什么时候从队列往外拿元素(调用 poll 方法)。

while 循环每执行一次,都会往外拿一个元素,但想往队列里放元素,可就有很多限制了,必须满足下面这个条件:

// 看看从 curNode 达到 nextNode 的距离是否会更短
if (distTo[nextNodeID] > distToNextNode) {// 更新 dp tabledistTo[nextNodeID] = distToNextNode;pq.offer(new State(nextNodeID, distToNextNode));
}

这也是为什么我说 distTo 数组可以理解成我们熟悉的 dp table,因为这个算法逻辑就是在不断的最小化 distTo 数组中的元素:
如果你能让到达 nextNodeID 的距离更短,那就更新 distTo[nextNodeID] 的值,让你入队,否则的话对不起,不让入队。
因为两个节点之间的最短距离(路径权重)肯定是一个确定的值,不可能无限减小下去,所以队列一定会空,队列空了之后,distTo 数组中记录的就是从 start 到其他节点的「最短距离」。

第二个问题解答

如果你非要用普通队列,其实也没问题的,你可以直接把 PriorityQueue 改成 LinkedList,也能得到正确答案,但是效率会低很多。

Dijkstra 算法使用优先级队列,主要是为了效率上的优化,类似一种贪心算法的思路。

为什么说是一种贪心思路呢,比如说下面这种情况,你想计算从起点 start 到终点 end 的最短路径权重:
在这里插入图片描述
假设你当前只遍历了图中的这几个节点,那么你下一步准备遍历那个节点?这三条路径都可能成为最短路径的一部分,但你觉得哪条路径更有「潜力」成为最短路径中的一部分?

从目前的情况来看,显然橙色路径的可能性更大嘛,所以我们希望节点 2 排在队列靠前的位置,优先被拿出来向后遍历。

所以我们使用 PriorityQueue 作为队列,让 distFromStart 的值较小的节点排在前面,这就类似我们之前讲
贪心算法 说到的贪心思路,可以很大程度上优化算法的效率。

第三个问题解答

肯定可以的,因为我们标准 Dijkstra 算法会算出 start 到所有其他节点的最短路径,你只想计算到 end 的最短路径,相当于减少计算量,当然可以提升效率。

需要在代码中做的修改也非常少,只要改改函数签名,再加个 if 判断就行了:

// 输入起点 start 和终点 end,计算起点到终点的最短距离
int dijkstra(int start, int end, List<Integer>[] graph) {// ...while (!pq.isEmpty()) {State curState = pq.poll();int curNodeID = curState.id;int curDistFromStart = curState.distFromStart;// 在这里加一个判断就行了,其他代码不用改if (curNodeID == end) {return curDistFromStart;}if (curDistFromStart > distTo[curNodeID]) {continue;}// ...}// 如果运行到这里,说明从 start 无法走到 endreturn Integer.MAX_VALUE;
}

因为优先级队列自动排序的性质,每次从队列里面拿出来的都是 distFromStart 值最小的,所以当你第一次从队列中拿出终点 end 时,此时的 distFromStart 对应的值就是从 start 到 end 的最短距离。
这个算法较之前的实现提前 return 了,所以效率有一定的提高。

http://www.dtcms.com/wzjs/184438.html

相关文章:

  • 好的网站建设公司百度移动权重
  • 成都网站建设哪家强聊城seo培训
  • 做网站片头的软件关键词挖掘站长
  • 网站建设收费价目表哪家网络公司比较好
  • 泰安网站建设公司怎样推广自己的产品
  • 做捕鱼网站电话号码开封网站推广
  • 做微信网站的公司泰州seo网络公司
  • 北京王府井大街好口碑关键词优化地址
  • 如何用个人电脑做网站超级外链工具 增加外链中
  • 网站建设及维护协议攀枝花网站seo
  • 优化什么建立生育支持政策体系北京seo收费
  • 做英文网站网上推广培训
  • 滁州注册公司流程和费用整站优化代理
  • 长沙网站建设定制广州品牌营销服务
  • 金融培训网站源码seo外链怎么做
  • 个人网站建设的收获微信公众号怎么创建
  • 哪里有免费的网站域名新闻源
  • 低价备案域名购买seo在线培训机构排名
  • 17网站一起做网店优势与劣势优化大师班级
  • 网站建设的价值关键词站长工具
  • 如何自建一个便宜的网站网游推广员
  • 人才网站建设的目标公关服务
  • 义乌seo厦门seo排名收费
  • jsp动态网站开发项目教程 ppt微信群推广网站
  • 网站怎么做查询系统seo百度刷排名
  • 网站建设做哪 个会计科目茶叶推广软文
  • 网站建设自建与租用区别百度小程序seo
  • 南宁机关两学一做网站网站建设网站
  • 合肥做网站需要多少钱网络营销策略内容
  • 淘客网站如何做能加快收录线上推广的三种方式