(JAVA)贪心算法、加权有向图与求得最短路径的基本论述与实现

1. 贪心算法

1.1 贪心算法的概述:

贪心算法是一种对某些求最优解问题的更简单、更迅速的设计技术

贪心算法的特点是一步一步地进行,常以当前情况为基础根据某个优化测度作最优选择,而不考虑各种可能的整体情况,省去了为找最优解要穷尽所有可能而必须耗费的大量时间。

贪心算法采用自顶向下,以迭代的方法做出相继的贪心选择,每做一次贪心选择,就将所求问题简化为一个规模更小的子问题,通过每一步贪心选择,可得到问题的一个最优解。

虽然每一步上都要保证能获得局部最优解,但由此产生的全局解有时不一定是最优的,所以贪心算法不要回溯

1.2 贪心算法适用的问题

贪心策略的前提是:局部最优策略能导致产生全局最优解

实际上,贪心算法使用的情况比较少,一般对一个问题分析是否适用于贪心算法,可以先选择该问题下的几个实际数据进行分析可以做出判断。

1.3 贪心算法的实现框架

从问题的某一初始解出发:

while (能朝给定总目标前进一步)
{ 利用可行的决策,求出可行解的一个解元素;
}

所有解元素组合成问题的一个可行解。

1.4 贪心策略的选择

用贪心算法只能通过解局部最优解的策略来达到全局最优解,因此一定要注意判断问题是否适合采用贪心算法策略,找到解是否一定是问题的最优解。

1.5 例题分析

1.5.1 分糖果问题

n个小朋友玩完游戏后,老师准备给他们发糖果;每个人有一个分数a[i],如果比左右的人分数高,那么糖果也要比左右的多,并且每个小朋友至少有一颗。问老师最少准备多少糖果?

这个题目不能直接用动态规划去解,比如用dp[i]表示前i个人需要的最少糖果数。
因为(前i个人的最少糖果数)这种状态表示会收到第i+1个人的影响,如果a[i]>a[i+1],那么第i个人应该比第i+1个人多。即是这种状态表示不具备无后效性。
如果是我们分配糖果,我们应该怎么分配?

  • 答案是:从分数最低的开始。
    按照分数排序,从最低开始分,每次判断是否比左右的分数高。

假设每个人分c[i]个糖果,那么对于第i个人有c[i]=max(c[i-1],c[c+1])+1;

(c[i]默认为0,如果在计算i的时候,c[i-1]为0,表示i-1的分数比i高)

但是,这样解决的时间复杂度为O(NLogN),主要瓶颈是在排序。如果提交,会得到Time Limit Exceeded的提示。

  • 因此我们需要对贪心的策略进行优化:
    我们把左右两种情况分开看。
    • 如果只考虑比左边的人分数高时,容易得到策略:
      从左到右遍历,如果a[i]>a[i-1],则有c[i]=c[i-1]+1;否则c[i]=1。
    • 再考虑比右边的人分数高时,此时我们要从数组的最右边,向左开始遍历:
      如果a[i]>a[i+1], 则有c[i]=c[i+1]+1;否则c[i]不变;
  • 这样讲过两次遍历,我们可以得到一个分配方案,并且时间复杂度是O(N)

1.5.2 小船过河问题

n个人要过河,但是只有一艘船;船每次只能做两个人,每个人有一个单独坐船的过河时间a[i],如果两个人(x和y)一起坐船,那过河时间为a[x]和a[y]的较大值。问最短需要多少时间,才能把所有人送过河?

题目给出关键信息:1、两个人过河,耗时为较长的时间;
还有隐藏的信息:2、两个人过河后,需要有一个人把船开回去;
要保证总时间尽可能小,这里有两个关键原则:应该使得两个人时间差尽可能小(减少浪费),同时船回去的时间也尽可能小(减少等待)。
先不考虑空船回来的情况,如果有无限多的船,那么应该怎么分配?

  • 答案:每次从剩下的人选择耗时最长的人,再选择与他耗时最接近的人。

再考虑只有一条船的情况,假设有A/B/C三个人,并且耗时A<B<C。
那么最快的方案是:A+B去, A回;A+C去;总耗时是A+B+C。(因为A是最快的,让其他人来回时间只会更长,减少等待的原则
如果有A/B/C/D四个人,且耗时A<B<C<D,这时有两种方案:
1、最快的来回送人方式,A+B去;A回;A+C去,A回;A+D去; 总耗时是B+C+D+2A (减少等待原则)
2、最快和次快一起送人方式,A+B先去,A回;C+D去,B回;A+B去;总耗时是 3B+D+A (减少浪费原则)
对比方案1、2的选择,我们发现差别仅在A+C和2B;

  • 为何方案1、2差别里没有D?

因为D最终一定要过河,且耗时一定为D。

如果有A/B/C/D/E 5个人,且耗时A<B<C<D<E,这时如何抉择?
仍是从最慢的E看。(参考我们无限多船的情况)

  1. 方案1,减少等待;先送E过去,然后接着考虑四个人的情况;
  2. 方案2,减少浪费;先送E/D过去,然后接着考虑A/B/C三个人的情况;(4人的时候的方案2)

到5个人的时候,我们已经明显发了一个特点:问题是重复,且可以由子问题去解决。

根据5个人的情况,我们可以推出状态转移方程

  • dp[i] = min(dp[i - 1] + a[i] + a[1], dp[i - 2] + a[2] + a[1] + a[i] + a[2]);

再根据我们考虑的1、2、3、4个人的情况,我们分别可以算出dp[i]的初始化值:

dp[1] = a[1];
dp[2] = a[2];
dp[3] = a[2]+a[1]+a[3];
dp[4] = min(dp[3] + a[4] + a[1], dp[2]+a[2]+a[1]+a[4]+a[2]);

由上述的状态转移方程和初始化值,我们可以推出dp[n]的值。

1.5.3 背包问题

问题描述 有一个背包,背包容量是M=150。有7个物品,物品可以分割成任意大小。要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。

在这里插入图片描述

**问题分析: **

  1. 目标函数: ∑pi最大,使得装入背包中的所有物品pi的价值加起来最大。

  2. 约束条件:装入的物品总重量不超过背包容量:∑wi<=M( M=150)

  3. 贪心策略:

    • 选择价值最大的物品
    • 选择价值最大的物品
    • 选择单位重量价值最大的物品

有三个物品A,B,C,其重量分别为{30,10,20},价值分别为{60,30,80},背包的容量为50,

  • 分别应用三种贪心策略装入背包的物品和获得的价值如下图所示:

在这里插入图片描述

算法的三种策略:

  • 算法设计:
  1. 计算出每个物品单位重量的价值
  2. 按单位价值从大到小将物品排序
  3. 根据背包当前所剩容量选取物品
  4. 如果背包的容量大于当前物品的重量,那么就将当前物品装进去。否则,那么就将当前物品舍去,然后跳出循环结束。

2. 加权有向图

与加权无向图不同的时。这种图的特点是边有方向性,即边从一个顶点指向另一个顶点,并且每条边都有一个与之相关的权重,这个权重通常代表了从一点到另一点的成本或距离。

2.1 加权有向图边的表示

2.1.1 API设计

类名DirectedEdge
构造方法DirectedEdge(int v,int w,double weight):通过顶点v和w,以及权重weight值构造一个边对象
成员方法1. public double weight():获取边的权重值
2. public int from():获取有向边的起点
3. public int to():获取有向边的重点
成员变量1. private final int V:起点
2. private final int W:终点
3. private final double weight:当前边的权重

2.2 加权有向图的实现

2.2.1 API 设计

类名EdgeWeightedDigraph
构造方法EdgeWeightedDigraph(DirectedEdge V):创建一个包含V个顶点但不包含边的有向图
成员方法1. public int V():获取图中顶点的数量
2. public int E():获取图中边的数量
3. public void addEdge(DirectedEdge e):向有向图中添加一条边e
4. public Queue<DirectedEdge> adj(int v):获取由v指出的边所连接的所有顶点
5. public Queue<DirectedEdge> edges():获取加权有向图的所有边
成员变量1. private final int V:记录顶点数量
2. private int E:记录边数量
3. private Queue<DirectedEdge>[] adj:邻接表

2.2.2 代码实现

package com.renecdemo.weighted;import com.renecdemo.graph.Queue;/*** 加权有向图*/
public class EdgeWeightedDigraph {private final int V;// 记录顶点数量private int E;// 记录边数量private Queue<DirectedEdge>[] adj;// 邻接表public EdgeWeightedDigraph(int v) {this.V = v;this.E = 0;this.adj = new Queue[V];for (int i = 0; i < adj.length; i++) {adj[i] = new Queue<>();}}public int V(){return V;}public int E(){return E;}/*** 向有向图中添加一条边e* @param e*/public void addEdge(DirectedEdge e){// 因为e是有方向的,所以只需要让e出现在起点的邻接表中即可int v = e.from();adj[v].enqueue(e);E++;}/*** 获取由 v顶点 指出的边所连接的所有顶点 - 返回该顶点所在的邻接表即可* @param v 顶点* @return*/public Queue<DirectedEdge> adj(int v){return adj[v];}/*** 获取加权有向图的所有边* @return*/public Queue<DirectedEdge> edges(){// 遍历图中的每一个顶点Queue<DirectedEdge> allEdges = new Queue<>();for (int v = 0; v < V; v++) {for (DirectedEdge e : adj[v]) {allEdges.enqueue(e);}}return allEdges;}}

3. 最短路径

有了加权有向图之后,我们立刻就可以联想到在实际生活汇总的使用场景,例如在一副地图中,找到顶点a和顶点b之间的路径,这条路径可以是距离最短,也可以是时间最短,也可以是费用最小等,如果我们把距离/时间/费用看作是成本,那么就需要找到顶点a和顶点b之间成本最小的路径。

3.1 最短路径的 定义以及性质

3.1.1 定义:

  • 在一副加权有向图中,从顶点s到顶点t的最短路径是所有从顶点s到顶点t的路径中总权重最小的那条路径

在这里插入图片描述

3.1.2 性质:

  1. 路径具有方向性
  2. 权重不一定等价于距离,权重可以是距离、时间、花费等内容,权重最小指的是成本最低
  3. 只考虑连通图,一副图中并不是所有的顶点都是可达的,如果s和t不可达,那么它们之间也就不存在最短路径。为了简化问题,这里只考虑连通图
  4. 最短路径不一定是唯一的。从一个顶点到达另一个顶点的权重最小的路径可能会有很多条,这里只需要找出一条即可

3.1.3 最短路径树

给定一副加权有向图和一个顶点s,以s为起点的一颗最短路径树是图的一副子图,它包含顶点s以及从s可达的所有顶点。

这颗有向图的根节点为s,树的每条路径都是有向图中的一条最短路径

3.2 最短路径树的API设计

类名DijkstraSP
构造方法pulbic DijkstraSP(EdgeWeightedDigraph G,int s):根据一副加权有向图G和顶点s,创建一个计算顶点为s的最短路径树对象
成员方法1. private void relax(EdgeWeightedDigraph G,int v):松弛图G中的顶点
2. public double disTo(int v):获取从顶点s到顶点v的最短路径的总权重
3. public boolean hasPathTo(int v):判断从顶点s到顶带你v是否可达
4. public Queue<DirectedEdge> pathTo(int v):查询从起点s到顶点v的最短路径中所有的边
成员变量1. private DirectedEdge[] edgeTo:索引代表顶点,指表示从顶点s到当前顶点的最短路径上的最后一条边
2. private double[] distTo:索引代表顶点,值从顶点s到当前的最短路径的总权重
3. private IndexMinPriorityQueue<Double> pq:存放树种顶点到非树中顶点之间的有效横切边

3.2 松弛技术

3.2.1 松弛技术的概述

松弛这个词来源于生活:一条橡皮筋沿着两个顶点的某条路径紧紧展开,如果这两个顶点之间的路径不止一条,还有存在更短的路径,那么把皮筋转移到更短的路径上,皮筋就可以放松了。

在这里插入图片描述

松弛这种简单的原理刚好可以用来计算最短路径树。

在我们的API中,需要用到两个成员变量edgeTo和distTo,分别存储边和权重。一开始给定一幅图G和顶点s,我们只知道图的边以及这些边的权重,其他的一无所知,此时初始化顶点s到顶点s的最短路径的总权重disto[s]=0;顶点s到其他顶点的总权重默认为无穷大,随着算法的执行,不断的使用松弛技术处理图的边和顶点,并按一定的条件更新edgeTo和distTo中的数据,最终就可以得到最短路径树。

3.2.2 边的松弛:

放松边v->w意味着检查从s到w的最短路径是否先从s到v,然后再从v到w?

  • 如果是,则v-w这条边需要加入到最短路径树中,更新edgeTo和distTo中的内容:edgeTo[w]=表示v->w这条边的DirectedEdge对象,distTo[w]=distTo[v]+v->w这条边的权重;

  • 如果不是,则忽略v->w这条边。

在这里插入图片描述

3.2.3顶点的松弛:

顶点的松弛是基于边的松弛完成的,只需要把某个顶点指出的所有边松弛,那么该顶点就松弛完毕。例如要松弛顶点v,只需要遍历v的邻接表,把每一条边都松弛,那么顶点v就松弛了。

如果把起点设置为顶点0,那么找出起点0到顶点6的最短路径0->2->7>3->6的过程如下:

在这里插入图片描述

3.3 Dijkstra 算法的代码实现

package com.renecdemo.dijkstra;import com.renecdemo.graph.Queue;
import com.renecdemo.queue.IndexMinPriorityQueue;
import com.renecdemo.weighted.DirectedEdge;
import com.renecdemo.weighted.EdgeWeightedDigraph;/*** Dijkstra算法*/
public class DijkstraSP {// 索引代表顶点,值表示从顶点s到当前顶点的最短路径上的最后一条边private DirectedEdge[] edgeTo;// 索引代表顶点,值从顶点s到当前的最短路径的总权重private double[] distTo;// 存放树种顶点到非树中顶点之间的有效横切边private IndexMinPriorityQueue<Double> pq;/*** 根据一副加权有向图G和顶点s,创建一个计算顶点为s的最短路径树对象* @param G* @param s*/public DijkstraSP(EdgeWeightedDigraph G, int s){// 初始化成员变量this.edgeTo = new DirectedEdge[G.V()];this.distTo = new double[G.V()];// 初始化权重数组,所有边的权重都为Double类型的无限大for (int i = 0; i < distTo.length; i++) {distTo[i] = Double.POSITIVE_INFINITY;}this.pq = new IndexMinPriorityQueue<>(G.V());// 找到图G中以顶点s为起点的最短路径树// 默认让s进入到最短路径树中distTo[s] = 0.0;pq.insert(s,0.0);while (!pq.isEmpty()){relax(G,pq.delMin()); // 弹出最新规划出的顶点}}/*** 松弛图G中的顶点 - 找出最短路径树* @param G 指定的图* @param v 起点所至的顶点*/private void relax(EdgeWeightedDigraph G,int v){// 遍历 v顶点 的邻接表for (DirectedEdge e : G.adj(v)) {// 获取到该边的终点int w = e.to();// 通过e边 达到 v顶点 的另一个顶点/*通过松弛技术,判断从s到w的最短路径是否需要先从顶点s到顶点v,如何再由顶点v到顶点w判断:从起点到达 v顶点的权重+e边的权重 是否小于 起点直接到达 w顶点的权重*/if (distTo(v)+e.weight() < distTo(w)){// 变换distTo[w] = distTo(v)+e.weight();edgeTo[w] = e;// 判断pq中是否已经存在顶点wif (pq.contains(w)){pq.changeItem(w,distTo(w));}else {pq.insert(w,distTo(w));// 更新pq队列}}}}/*** 获取从顶点s到顶点v的最短路径的总权重* @param v* @return*/public double distTo(int v){return distTo[v];}/*** 判断从顶点s到顶带你v是否可达* @param v* @return*/public boolean hasPathTo(int v){return distTo[v]<Double.POSITIVE_INFINITY;}/*** 查询从起点s到顶点v的最短路径中所有的边* @param v* @return*/public Queue<DirectedEdge> pathTo(int v){// 判断顶点s到顶点v是否可达if (!hasPathTo(v)){return null;}// 创建队列对象Queue<DirectedEdge> allEdges = new Queue<>();// 顶点逆推while (true){// 得到v顶点的边DirectedEdge e = edgeTo[v];if (e==null){break;}allEdges.enqueue(e);// 更新 v顶点 —— e.from():获得e边的除了v顶点的另外一个顶点v = e.from();}// 返回队列return allEdges;}
}

4. 前置文章

  1. 浅入数据结构 “堆” - 实现和理论
  2. 开始熟悉 “二叉树” 的数据结构
  3. 队列 和 符号表 两种数据结构的实现
  4. 队列的进阶结构-优先队列
  5. 2-3树思想与红黑树的实现与基本原理
  6. B树和B+树的实现原理阐述
  7. 图的基本原理和API实现
  8. 有向图与拓扑排序的实现原理与基本实现
  9. 加权无向图和最小生成树的实现与原理概述

5. ES8 如何使用?

快来看看这篇好文章吧~~!!
😊👉(全篇详细讲解)ElasticSearch8.7 搭配 SpringDataElasticSearch5.1 的使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/452023.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode-3192 使二进制数组全部等于1的最少操作次数Ⅱ

今天的每日一题就是昨天的延伸&#xff0c;预判成功。 LeetCode-3191 使二进制数组全部等于1的最少操作次数-CSDN博客文章浏览阅读115次。如果数组第一个元素就是0&#xff0c;那么第一个元素是肯定要翻转的&#xff0c;而我们只有从索引0的位置开始翻转才可以翻转到第一个元素…

生成模型初认识

生成模型初认识 参考学习资料&#xff1a;李宏毅-机器学习 以下为课程过程中的简易笔记 生成模型 为什么要用生成模型&#xff1f;——创造力&#xff1a;同一个输入&#xff0c;产生不同的输出&#xff08;distribution&#xff09;&#xff0c;有一定概率发生某种随机事件…

【天池比赛】【零基础入门金融风控 Task2赛题理解】【2.3.6】

【天池比赛】【零基础入门金融风控 Task2赛题理解】【2.3.1-2.3.5】 2.3.6 变量分布可视化 2.3.6.1 单一变量分布可视化 对于 pandas.core.series.Series 类型的变量&#xff1a; index&#xff1a;含义&#xff1a;它表示 Series 对象的索引&#xff0c;也就是每个数据点对…

MySQL-15.DQL-排序查询

一.DQL-排序查询 -- 排序查询 -- 1.根据入职时间&#xff0c;对员工进行升序排序 select * from tb_emp order by entrydate asc ;-- 2.根据入职时间&#xff0c;对员工进行降序排序 select * from tb_emp order by entrydate desc ;-- 3.根据 入职时间 对公司员工进行 升序排序…

人工神经网络(Artificial Neural Networks,简称ANNs)-激活函数-5

建议在阅读本文之前先了解神经网络。 在构建神经网络的过程中,您需要做出的选择之一是在隐藏层和网络的输出层使用什么是激活函数。本文讨论了神经网络中的激活函数。 目录 ​​​​​​​ 什么是激活函数?神经网络的元素为什么我们需要非线性激活函数?激活函数的变体 …

质因数分解

#include <stdio.h>int main() {long long x;while (scanf("%lld", &x) ! EOF) { // 读取输入直到文件结束if (x 0) break; // 如果输入为0则退出循环for (long long i 2; i * i < x; i) {while (x % i 0) { // 当x能被i整除时printf("%lld &q…

Leetcode 组合总和

这个Java代码实现的是LeetCode上的“组合总和”&#xff08;Combination Sum&#xff09;问题&#xff0c;采用的是回溯算法&#xff08;Backtracking&#xff09;。下面是详细的算法思想解释&#xff1a; 算法思想&#xff1a; 回溯算法的基本思路&#xff1a; 回溯算法是一种…

考研前所学的c语言01(2024/10/15)

1.变量由字母数字下划线组成&#xff0c;但是首字母只能是字母和下划线 2.基本函数01 3.基本代码02&#xff08;符号常量&#xff09; 4. A 是字符常量&#xff08;character constant&#xff09;。它表示单个字符&#xff0c;并且它的类型是 char&#xff0c;一个字节 "…

无极低码课程【redis windows下服务注册密码修改】

下载Windows版本的Redis linux环境 (自行下载) 1.打开官网https://redis.io/downloads/ windows环境 1.打开github https://github.com/microsoftarchive/redis/releases 然后选择你喜欢的版本zip或msi下载 2.这里下载zip版,解压后后,打开安装目录 3.双击redis-server…

LabVIEW智能螺杆空压机测试系统

基于LabVIEW软件开发的螺杆空压机测试系统利用虚拟仪器技术进行空压机的性能测试和监控。系统能够实现对螺杆空压机关键性能参数如压力、温度、流量、转速及功率的实时采集与分析&#xff0c;有效提高测试效率与准确性&#xff0c;同时减少人工操作&#xff0c;提升安全性。 项…

ZW3D二次开发_文件_修改文件引用

1.假设零件图纸与工程图图纸关联&#xff08;默认情况下在零件图纸中新建工程图图纸会自动关联&#xff09; 可以通过查询-》关联文件 查看关联的文件 此时可以查看到零件图纸所关联的工程图图纸 当工程图图纸名字修改后&#xff0c;上图文件列表中的工程图图纸名将对应不上&a…

时空数据时序预测模型: HA、VAR、GBRT、GCN、DCRNN、FCCF、ST-MGCN

HA (Historical Average) HA (Historical Average&#xff0c;历史平均模型) 是一种基础的时间序列预测方法&#xff0c;通常用于预测具有周期性或季节性规律的数据。它通过计算历史上同一时间段的平均值来预测未来值&#xff0c;假设数据会遵循某种周期性的变化模式。以下是对…

Java项目-基于Springboot的智慧养老平台项目(源码+文档).zip

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 开发运行环境 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、SpringClud、Vue、Mybaits Plus、ELementUI工具&…

车辆管理新篇章:SpringBoot技术解析

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

【计算机网络 - 基础问题】每日 3 题(四十七)

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞…

Oracle数据库系统表空间过大,清理SYSTEM、SYSAUX表空间

一.前言 在oracle数据库中&#xff0c;system为系统表空间&#xff0c;存放着一些我们经常用到的系统表和视图&#xff0c;sysaux为辅助表空间&#xff0c;辅助着系统表空间。这两个表空间不宜添加数据文件&#xff0c;会使系统表空间过于臃肿&#xff0c;从而影响数据库的使用…

014_django基于大数据运城市二手房价数据可视化系统的设计与实现2024_3ahrxq75

目录 系统展示 开发背景 代码实现 项目案例 获取源码 博主介绍&#xff1a;CodeMentor毕业设计领航者、全网关注者30W群落&#xff0c;InfoQ特邀专栏作家、技术博客领航者、InfoQ新星培育计划导师、Web开发领域杰出贡献者&#xff0c;博客领航之星、开发者头条/腾讯云/AW…

Ajax处理错误信息(处理响应报文)

<!DOCTYPE html> <html><head><meta charset"utf-8" /><title></title></head><body><form action""><div>用户名<input type"text" class"username"></div>…

IDEA如何配置自己的maven和maven设置阿里云仓库

前言 我们在使用IDEA开发Java应用时&#xff0c;一般是需要配置maven仓库的&#xff0c;那么我们应该如何配置呢&#xff1f;此外&#xff0c;默认的maven仓库下载速度很慢&#xff0c;我们一般可以配置阿里云或者华为云仓库&#xff0c;这个又应该怎么配置呢&#xff1f; 如…

(小白教程)MPV.NET 播放器安装和添加Bilibili弹幕

MPV.NET安装和添加脚本 MPV跨平台播放器&#xff1a;该播放器基于流行的mpv媒体播放器。mpv.net 设计为与 mpv 兼容&#xff0c;几乎所有 mpv 功能都可用&#xff0c;这意味着官方mpv 手册适用于 mpv.net&#xff0c;差异记录在mpv.net 手册中。 主要差异是mpv.net为MPV添加了现…