六种图算法的python实现

news2024/10/6 12:24:47

六种图算法的python实现

1. Prim 算法

基本原理

Prim算法是一种求解最小生成树的贪心算法。所谓最小生成树,就是对于给定的连通图,找到一棵包含所有顶点的树,且树上所有边的权重之和最小。Prim算法从一个顶点开始,每次选择与当前生成树距离最短的顶点加入到生成树中,直到所有顶点都加入为止。

应用场景

Prim算法广泛应用于网络设计、电路设计、道路规划等领域,其中需要找到连接所有点的最小成本路径。例如,在铺设电缆或道路网络中,可以使用Prim算法来找到连接所有地点所需的最小成本路径。

优缺点

优点

  1. Prim算法能够找到全局最优解,即最小生成树。
  2. 适用于稠密图,即边数较多的图。

缺点

  1. 对于稀疏图(边数较少的图),Prim算法可能不是最高效的选择。
  2. Prim算法需要频繁地查找和更新距离,因此在实现上可能需要使用优先队列等数据结构来提高效率。
Python 实现

以下是一个简单的Prim算法的Python实现:

import heapq

def prim(graph):
    # 初始化
    start_node = 'A'  # 可以选择任意节点作为起始节点
    visited = set([start_node])  # 已访问节点的集合
    edges = [
        (cost, start_node, to)
        for to, cost in graph[start_node].items()
    ]  # 初始可选边集合
    heapq.heapify(edges)  # 使用堆来优化查找最小边的过程
    mst = []  # 最小生成树的边
    total_cost = 0  # 最小生成树的总权重

    while edges:
        cost, frm, to = heapq.heappop(edges)  # 弹出权重最小的边
        if to not in visited:  # 如果目标节点未被访问过
            visited.add(to)  # 将其标记为已访问
            mst.append((frm, to, cost))  # 将这条边加入最小生成树
            total_cost += cost  # 更新总权重
            # 将与新加入节点相连且未访问过的节点(及其边)加入堆中
            for to_next, cost2 in graph[to].items():
                if to_next not in visited:
                    heapq.heappush(edges, (cost2, to, to_next))

    return mst, total_cost

# 示例图(以字典形式表示,键为起点,值为一个字典,表示从起点到各个终点的权重)
graph = {
    'A': {'B': 2, 'C': 3},
    'B': {'A': 2, 'C': 1, 'D': 1, 'E': 4},
    'C': {'A': 3, 'B': 1, 'F': 5},
    'D': {'B': 1, 'E': 1},
    'E': {'B': 4, 'D': 1, 'F': 1},
    'F': {'C': 5, 'E': 1, 'G': 1},
    'G': {'F': 1}
}

mst, total_cost = prim(graph)
print("最小生成树的边:", mst)
print("最小生成树的总权重:", total_cost)

原始图:

在这里插入图片描述

最小生成树:

在这里插入图片描述

这个实现使用了优先队列(通过Python的heapq模块实现)来优化查找最小边的过程。注意,这个实现假设图是连通的,且权重都是正数。如果图不连通,或者存在负权重的边,那么这个实现可能不适用。

2. Kruskal 算法

基本原理

Kruskal算法是一种用于查找最小生成树的算法,属于贪心算法的一种。在一个加权无向图中,最小生成树是指一个边集,它能够连接所有的顶点,并且所有边的权值之和最小,而且不包含环。

Kruskal算法的基本思想是:

  1. 将图中的所有边按照权重从小到大排序。
  2. 从最小的边开始,依次选择边,每次选择一条边后,判断这条边是否会与已选择的边形成环。
  3. 如果不会形成环,则将这条边加入到最小生成树中;否则,放弃这条边。
  4. 重复步骤2和3,直到所有的顶点都连接在一起或者所有的边都已被考虑过。
应用场景

Kruskal算法在多个领域有广泛的应用,包括但不限于:

  • 网络设计:在构建计算机网络、电力网络或交通网络时,需要找到连接所有节点的最小成本树。
  • 电路设计:在电子设计中,需要找到连接所有组件的最短电线长度。
优缺点

优点

  • 算法简单易懂,容易实现。
  • 总是能找到全局最优解,即权重和最小的生成树。

缺点

  • 当图中的边数非常多时,排序操作可能会比较耗时。
  • 需要额外的数据结构(如并查集)来检测环的形成,增加了算法的复杂度。
Python 实现

下面是一个简单的Kruskal算法的Python实现,使用了并查集来检测环:

class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))
    
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        root_x = self.find(x)
        root_y = self.find(y)
        self.parent[root_x] = root_y

def kruskal(graph):
    edges = []
    for u in graph:
        for v, w in graph[u]:
            edges.append((w, u, v))
    edges.sort()  # 按权重排序
    
    uf = UnionFind(len(graph))
    mst = []
    for w, u, v in edges:
        if uf.find(u) != uf.find(v):
            uf.union(u, v)
            mst.append((u, v, w))
    return mst

# 示例图
graph = {
    0: [(1, 7), (2, 9), (5, 14)],
    1: [(0, 7), (2, 10), (3, 15)],
    2: [(0, 9), (1, 10), (3, 11), (5, 2)],
    3: [(1, 15), (2, 11), (4, 6)],
    4: [(3, 6), (5, 9)],
    5: [(0, 14), (2, 2), (4, 9)]
}

mst = kruskal(graph)
print("最小生成树的边:", mst)

原始图:

在这里插入图片描述

最小生成树:

在这里插入图片描述

这个代码示例中,graph是一个字典,表示图的邻接表形式。kruskal函数首先将所有边按照权重排序,然后使用并查集来检测并避免环的形成,最后返回最小生成树的边列表。

3. Floyd-Warshall 算法

基本原理

Floyd-Warshall 算法是一种用于寻找给定加权图中所有顶点对之间最短路径的算法。它适用于带权重的有向图或带权重的无向图,并且可以处理负权重的边,但不能处理含有负权重环的图。

算法的基本思想是通过逐步构建更长的路径来找到最短路径。它使用一个三维数组 dist[k][i][j] 来表示从顶点 i 到顶点 j 的、所有中间顶点来自集合 {0, 1, …, k} 的一条最短路径的权重。最终,当 k 等于图中顶点数量减一时,dist[k][i][j] 就是从 i 到 j 的最短路径长度。

在实际应用中,为了节省空间,通常会将三维数组简化为二维数组,通过逐步更新这个二维数组来记录最短路径。

应用场景

Floyd-Warshall 算法通常用于需要找到图中所有顶点对之间最短路径的场景,例如网络路由选择、社交网络中的最短关系链查找等。

优缺点

优点

  • 算法简单易懂,实现起来较为方便。
  • 能够处理带有负权重的边。
  • 可以一次性计算出所有顶点对之间的最短路径。

缺点

  • 时间复杂度和空间复杂度都是 O(n^3),其中 n 是图中的顶点数。对于大型图来说,这可能是一个问题。
  • 不能处理带有负权重环的图。
Python 实现

以下是一个简单的 Floyd-Warshall 算法的 Python 实现:

def floyd_warshall(graph):
    n = len(graph)
    dist = [[float('inf')] * n for _ in range(n)]

    # 直接从邻接矩阵复制权重到dist矩阵
    for i in range(n):
        for j in range(n):
            dist[i][j] = graph[i][j]
            # 设置对角线上的距离为0,表示节点到自身的距离为0
            if i == j:
                dist[i][j] = 0

    # Floyd-Warshall算法的核心部分
    for k in range(n):
        for i in range(n):
            for j in range(n):
                if dist[i][k] != float('inf') and dist[k][j] != float('inf'):
                    dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
    return dist


# 示例图,使用邻接矩阵表示  
graph = [
    [0, 3, float('inf'), 5],
    [2, 0, float('inf'), 4],
    [float('inf'), 1, 0, float('inf')],
    [float('inf'), float('inf'), 2, 0]
]
print(floyd_warshall(graph))

这个实现中,graph 是一个邻接矩阵,表示图中的边和权重。float('inf') 表示无穷大,用于表示两个顶点之间没有直接连接的情况。

4. Bellman-Ford 算法

基本原理

Bellman-Ford 算法是一种用于在带权图中找出从单一源点到其他所有点的最短路径的算法。它适用于带有负权边的图,这是它与 Dijkstra 算法的一个重要区别。Bellman-Ford 算法的基本思想是对图中的所有边进行松弛操作,逐步逼近最短路径。

算法步骤如下:

  1. 初始化:设置源点到所有其他点的距离为无穷大(或一个非常大的数),源点到自身的距离为 0。
  2. 松弛操作:对所有边进行多次遍历(边的数量减 1 次),每次遍历时,对于图中的每一条边 (u, v),如果当前源点到点 u 的距离加上边 (u, v) 的权重小于源点到点 v 的当前距离,则更新源点到点 v 的距离为更小的值。
  3. 检查负权环:再进行一次边的遍历,如果仍有距离被更新,则说明图中存在负权环,因为在一个没有负权环的图中,最短路径的长度在经过 |V|-1 次松弛操作后就已经确定,其中 |V| 是顶点的数量。
应用场景

Bellman-Ford 算法适用于需要处理带有负权重的图的最短路径问题。例如,在路由选择、网络流优化、交通运输规划等领域中,边的权重可能表示时间、费用或距离,并且可能为负(例如,表示某种形式的“奖励”或“折扣”)。

优缺点

优点

  • 可以处理带有负权重的图。
  • 可以检测出负权环。
  • 算法实现相对简单。

缺点

  • 时间复杂度较高,为 O(|V|*|E|),其中 |V| 是顶点数,|E| 是边数。对于稠密图来说,这可能是一个问题。
  • 在没有负权重的图中,通常不如 Dijkstra 算法高效。
Python 实现

以下是一个简单的 Bellman-Ford 算法的 Python 实现:

class Graph:
    def __init__(self, vertices):
        self.V = vertices
        self.graph = []

    def add_edge(self, u, v, w):
        self.graph.append([u, v, w])

    def bellman_ford(self, src):
        dist = [float('inf')] * self.V
        dist[src] = 0

        # 松弛操作,进行 |V|-1 次
        for _ in range(self.V - 1):
            for u, v, w in self.graph:
                if dist[u] != float('inf') and dist[u] + w < dist[v]:
                    dist[v] = dist[u] + w

        # 检查负权环
        for u, v, w in self.graph:
            if dist[u] != float('inf') and dist[u] + w < dist[v]:
                return "图中存在负权环"

        return dist

# 使用示例
g = Graph(5)
g.add_edge(0, 1, -1)
g.add_edge(0, 2, 4)
g.add_edge(1, 2, 3)
g.add_edge(1, 3, 2)
g.add_edge(1, 4, 2)
g.add_edge(3, 2, 5)
g.add_edge(3, 1, 1)
g.add_edge(4, 3, -3)

print(g.bellman_ford(0))  # 输出从顶点 0 到其他各顶点的最短距离

这个实现创建了一个简单的图数据结构,并实现了 Bellman-Ford 算法来查找从指定源点到所有其他点的最短路径。注意,如果图中存在负权环,算法会返回相应的提示信息。

5. 强连通分量算法

基本原理

强连通分量算法主要用于在有向图中找出强连通分量。强连通分量是指在有向图中,任意两个顶点之间都存在一条路径,即它们是相互可达的。常见的强连通分量算法有Kosaraju算法和Tarjan算法。

这里,我们主要介绍Kosaraju算法,其基本原理是通过两次深度优先搜索(DFS)来找到强连通分量。

  1. 第一次DFS:对原始图进行深度优先搜索,并记录每个节点的完成时间(即DFS遍历结束时的时间)。

  2. 计算转置图:将原始图的所有边反向,得到转置图。

  3. 第二次DFS:根据第一次DFS记录的节点完成时间进行降序排序,然后按照这个顺序对转置图进行DFS。每次DFS遍历得到的子图就是一个强连通分量。

应用场景

强连通分量算法常用于社交网络分析、网页链接分析、程序控制流图分析等领域,用于找出紧密相关的群体或模块。

优缺点

优点

  • 能够准确地找出有向图中的强连通分量。
  • Kosaraju算法相对直观,易于理解。

缺点

  • 需要进行两次DFS,时间复杂度相对较高。
  • 需要额外的空间来存储转置图和节点的完成时间。
Python实现(Kosaraju算法)
from collections import defaultdict


class Graph:
    def __init__(self, vertices):
        self.V = vertices
        self.graph = defaultdict(list)

    def addEdge(self, u, v):
        self.graph[u].append(v)

    def DFSUtil(self, v, visited):
        visited.add(v)
        print(v, end='')
        for i in self.graph[v]:
            if i not in visited:
                self.DFSUtil(i, visited)

    def fillOrder(self, v, visited, stack):
        visited.add(v)
        for i in self.graph[v]:
            if i not in visited:
                self.fillOrder(i, visited, stack)
        stack.append(v)  # 修正这里,不要重新赋值给 stack

    def getTranspose(self):
        g = Graph(self.V)
        for i in self.graph:
            for j in self.graph[i]:
                g.addEdge(j, i)
        return g

    def printSCCs(self):
        stack = []
        visited = set()
        for i in range(self.V):
            if i not in visited:
                self.fillOrder(i, visited, stack)
        gr = self.getTranspose()
        visited = set()
        while stack:
            i = stack.pop()
            if i not in visited:
                gr.DFSUtil(i, visited)
                print()


# 使用示例
g = Graph(5)
g.addEdge(1, 0)
g.addEdge(0, 2)
g.addEdge(2, 1)
g.addEdge(0, 3)
g.addEdge(3, 4)
print("强连通分量为:")
g.printSCCs()

注意:上述代码是一个简化的示例,用于说明Kosaraju算法的基本原理。在实际应用中,可能需要根据具体需求进行适当的修改和优化。

这个Python实现中,Graph类表示一个有向图,addEdge方法用于添加边,DFSUtil方法用于执行深度优先搜索,fillOrder方法用于第一次DFS并记录节点的完成时间(通过栈的顺序隐式表示),getTranspose方法用于计算转置图,printSCCs方法用于找出并打印所有的强连通分量。

6. 拓扑排序算法

基本原理

拓扑排序(Topological Sorting)是针对有向无环图(DAG, Directed Acyclic Graph)的顶点的一种排序,它将有向无环图的顶点以线性序列的方式输出,对于每一条有向边 (u, v),顶点 u 在排序中都出现在顶点 v 之前。拓扑排序常用于任务调度、制定课程学习计划等场景。

拓扑排序的基本原理是通过不断移除入度为0的节点(即没有前驱或依赖的节点),并更新其相邻节点的入度,直到所有节点都被移除或者无法再移除入度为0的节点为止。如果还有剩余节点,则说明图中存在环,无法进行拓扑排序。

应用场景
  1. 任务调度:在项目管理中,常常需要确定任务的执行顺序,拓扑排序可以帮助确定哪些任务可以并行执行,哪些任务必须等待其他任务完成后才能开始。
  2. 制定学习计划:在学习多门有依赖关系的课程时,拓扑排序可以帮助规划学习顺序。
  3. 编译器中的指令重排:在编译器优化中,拓扑排序可以确保指令以正确的顺序执行,从而提高程序的执行效率。
优缺点

优点

  • 可以有效地确定有依赖关系的任务或操作的执行顺序。
  • 算法相对简单,容易实现。

缺点

  • 仅适用于有向无环图(DAG),如果图中存在环,则算法无法得出结果。
  • 拓扑排序的结果不唯一,因为可能存在多个入度为0的节点,这些节点的处理顺序可以不同。
Python实现

以下是一个简单的拓扑排序的Python实现:

from collections import defaultdict, deque


def topological_sort(graph):
    # 统计入度
    indegree = defaultdict(int)
    for node in graph:
        for neighbor in graph[node]:
            indegree[neighbor] += 1

    # 将入度为0的节点加入队列
    queue = deque([node for node in graph if indegree[node] == 0])
    result = []

    # 拓扑排序
    while queue:
        node = queue.popleft()
        result.append(node)
        # 将该节点的邻接节点的入度减1,并将入度为0的节点加入队列
        for neighbor in graph[node]:
            indegree[neighbor] -= 1
            if indegree[neighbor] == 0:
                queue.append(neighbor)

    # 如果结果中的节点数等于图中的节点数,则拓扑排序成功
    if len(result) == len(graph):
        return result
    else:
        return None


# 测试
graph = {
    'A': ['B', 'C'],
    'B': ['D', 'E'],
    'C': ['F'],
    'D': [],
    'E': ['F'],
    'F': []
}

sorted_nodes = topological_sort(graph)
if sorted_nodes:
    print("拓扑排序结果:", sorted_nodes)
else:
    print("图中存在环,无法进行拓扑排序")

这个示例中,graph是一个字典,表示有向图的结构,其中键是节点,值是该节点的相邻节点列表。topological_sort函数接受这个图结构作为输入,并返回一个可能的拓扑排序结果列表。如果图中存在环,则返回相应的错误信息。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[CUDA编程] cuda graph优化心得

CUDA Graph 1. cuda graph的使用场景 cuda graph在一个kernel要多次执行&#xff0c;且每次只更改kernel 参数或者不更改参数时使用效果更加&#xff1b;但是如果将graph替换已有的kernel组合&#xff0c;且没有重复执行&#xff0c;感觉效率不是很高反而低于原始的kernel调用…

使用fvm切换flutter版本

切换flutter版本 下载fvm 1、dart pub global activate fvm dart下载fvm 2、warning中获取下载本地的地址 3、添加用户变量path&#xff1a; 下载地址 终端查看fvm版本 fvm --version 4、指定fvm文件缓存地址 fvm config --cache-path C:\src\fvm&#xff08;自定义地址&…

北京多商入驻app开发项目的主要优势及功能

多商入驻app开发项目的定义 随着电子支付技术的不断成熟&#xff0c;全国各地的消费者通过网络在线上购物的频率越来越高&#xff0c;为此&#xff0c;多商入驻app开发项目应用而生。各商家也纷纷开始申请入驻商城平台&#xff0c;开设自己的店铺。 图片来源&#xff1a;unspl…

【Ardiuno】实验使用ESP32单片机连接Wifi(图文)

ESP32单片机最为精华和有特色的地方当然是wifi连接&#xff0c;这里我们就写程序实验一下适使用ESP32主板连接wifi&#xff0c;为了简化实验我们这里只做了连接部分&#xff0c;其他实验在后续再继续。 由于本实验只要在串口监视器中查看结果状态即可&#xff0c;因此电路板上…

Ubuntu server 24 (Linux) lvm 动态扩容磁盘空间

1 查看磁盘信息 sudo fdisk -l 2 查看lvm分区信息 sudo lvdisplay 3 扩展逻辑卷 sudo lvextend -l 100%FREE /dev/ubuntu-vg/ubuntu-lv 4 刷新逻辑卷 sudo resize2fs /dev/ubuntu-vg/ubuntu-lv 5 查看磁盘信息 df -h

[Shell编程学习路线]——编制第一个shell脚本入门篇

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f6e0;️Shell编程专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年6月12日10点23分 &#x1f004;️文章质量&#xff1a;93分 目录 ——前言—— &#x1f4a5;常用的几种shell Bash Sh …

【吊打面试官系列-Mysql面试题】什么是通用 SQL 函数?

大家好&#xff0c;我是锋哥。今天分享关于 【什么是通用 SQL 函数&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; 什么是通用 SQL 函数&#xff1f; 1、CONCAT(A, B) – 连接两个字符串值以创建单个字符串输出。通常用于将两个或多个字段合并为一个字段。 10…

40V/1A 步进电机驱动芯片SS6810R兼容BD68610

SS6810R是一款功能丰富的PWM电流驱动的双极低功耗电机驱动集成芯片&#xff0c;其工作电压范围&#xff1a;10V&#xff5e;40V&#xff1b;有两路H桥驱动&#xff0c;输出40V/1A&#xff1b;具有较大的输出能力和多种保护功能。它适用于各种电机驱动应用&#xff0c;能够提供稳…

Apollo9.0 PNC源码学习之Control模块(三)

本文将对Apollo的纵向控制器进行讲解&#xff0c;看完本文&#xff0c;你将会对百度Apollo的纵向控制有更深的理解 前面文章&#xff1a; Apollo9.0 PNC源码学习之Control模块&#xff08;一&#xff09; Apollo9.0 PNC源码学习之Control模块&#xff08;二&#xff09; 1 纵向…

c语言回顾-函数递归

1.递归的介绍 1.1什么是递归 递归是指在一个函数的定义中调用自身的过程。简单来说&#xff0c;递归是一种通过重复调用自身来解决问题的方法。 递归包括两个关键要素&#xff1a;基本情况和递归情况。基本情况是指当问题达到某个特定条件时&#xff0c;不再需要递归调用&am…

6.7.32 用于计算机辅助检测和诊断研究的精选乳房 X 线摄影数据集

由于在乳房 X 线摄影决策支持系统领域缺乏标准的评估数据集&#xff0c;已发表的研究结果很难复制&#xff1b;大多数乳房 X 线摄影中乳腺癌的计算机辅助诊断 (CADx) 和检测 (CADe) 算法都是在私人数据集或公共数据库的未指定子集上进行评估的。这导致无法直接比较方法的性能或…

MyBatis插件机制介绍与原理

插件简介 什么是插件 插件是一种软件组件&#xff0c;可以在另一个软件程序中添加功能或特性。插件通常被设计成可以 随时添加或删除 的&#xff0c;而不影响 主程序 的功能。插件可以 扩展 软件程序的功能&#xff0c;这让用户可以根据自己的需求定制软件&#xff0c;提高工作…

flutter报错You are currently using Java 1.8

flutter报错Could not run phased build action using connection to Gradle distribution ‘https://services.gradle.org/distributions/gradle-7.6.3-all.zip’.\r\norg.gradle.api.ProjectConfigurationException: A problem occurred configuring root project ‘android’…

物联网安全的优秀实践以及七种策略

大多数物联网安全漏洞都是可以预防的&#xff0c;甚至可能是全部。看看任何引人注目的物联网攻击&#xff0c;都会发现一个已知的安全漏洞。 2019年的Ring智能摄像头漏洞?用户可以创建弱密码并跳过多因素身份验证。2021年的Verkada监视服务攻击?该公司的系统中有太多的超级管…

SAP SO定价上面2个ZPR1 其中一个不活跃

查看价格表 取定价的时候排除不活动的 即可

冯喜运:6.12今日黄金原油行情还会涨吗?黄金原油独家操作策略

【黄金消息面分析】&#xff1a;据荷兰国际集团(ING)大宗商品策略师埃瓦?曼西(Ewa Manthey)称&#xff0c;黄金价格正面临来自美元走强和中国需求疲软的新阻力&#xff0c;但一旦美联储开始降息&#xff0c;黄金价格将恢复反弹。      【黄金技术面分析】&#xff1a;黄金…

易保全网络赋强公证系统,“公证赋强+科技赋能”双重增信

网络赋强公证系统是一种创新的法律服务模式&#xff0c;旨在通过线上方式赋予债权文书强制执行效力。具体来说&#xff0c;该系统结合了互联网技术与公证业务&#xff0c;允许公证机构根据当事人的申请&#xff0c;利用互联网公证技术手段对互联网上的债权文书进行公证&#xf…

基于深度学习的图像边缘和轮廓提取

导读&#xff1a;边缘和轮廓的提取是一个非常棘手的工作&#xff0c;细节也许就会被过强的图像线条掩盖&#xff0c;纹理&#xff08;texture&#xff09;本身就是一种很弱的边缘分布模式&#xff0c;分级&#xff08;hierarchical&#xff09;表示是常用的方法&#xff0c;俗称…

PWN环境配置

虚拟机安装 镜像下载网站(http://old-releases.ubuntu.com/releases/)虚拟机建议硬盘 256 G 以上&#xff0c;内存也尽量大一些。硬盘大小只是上界&#xff0c;256 G 不是真就占了 256G&#xff0c;而后期如果硬盘空间不足会很麻烦。lsb_release -a查看版本更换 ubuntu 镜像源…

【教程】怎么给网站添加弹窗广告代码javascript

由于最近支付宝悬赏领红包活动比较多邀请别人扫码自己也有奖励于是就想到了给自己网站上添加一个这种弹窗广告用户可以自己领取红包 效果图 代码也很简单下面附上代码 首先引入jquery <script src”https://pay.codewo.cn/static/index/user/assets/vendor/libs/jquery/j…