图的概念、性质和存储与简单遍历

前置知识:树的基本概念及性质

为了保证学习效果,请保证已经掌握前置知识之后,再来学习本章节!如果在阅读中遇到困难,也可以回到前面章节查阅。

学习目标

  • 掌握图的基本概念
  • 掌握图的一些性质

图的概念

基本概念

图 (Graph) 是一个二元组 𝐺=(𝑉(𝐺),𝐸(𝐺))G=(V(G),E(G)) 。其中 𝑉(𝐺)V(G) 是非空集,称为 点集 (Vertex set) ,对于 𝑉V 中的每个元素,我们称其为 顶点 (Vertex) 或 节点 (Node) ,简称  ; 𝐸(𝐺)E(G) 为 𝑉(𝐺)V(G) 各结点之间边的集合,称为 边集 (Edge set) 。

常用 𝐺=(𝑉,𝐸)G=(V,E) 表示图。

当 𝑉,𝐸V,E 都是有限集合时,称 𝐺G 为 有限图 。

当 𝑉V 或 𝐸E 是无限集合时,称 𝐺G 为 无限图 。

图有多种,包括 无向图 (Undirected graph) , 有向图 (Directed graph) , 混合图 (Mixed graph) 等

若 𝐺G 为无向图,则 𝐸E 中的每个元素为一个无序二元组 (𝑢,𝑣)(u,v) ,称作 无向边 (Undirected edge) ,简称 边 (Edge) ,其中 𝑢,𝑣∈𝑉u,v∈V 。设 𝑒=(𝑢,𝑣)e=(u,v) ,则 𝑢u 和 𝑣v 称为 𝑒e 的 端点 (Endpoint) 。

若 𝐺G 为混合图,则 𝐸E 中既有向边,又有无向边。

若 𝐺G 的每条边 𝑒𝑘=(𝑢𝑘,𝑣𝑘)ek​=(uk​,vk​) 都被赋予一个数作为该边的  ,则称 𝐺G 为 赋权图 。如果这些权都是正实数,就称 𝐺G 为 正权图 。

形象地说,图是由若干点以及连接点与点的边构成的。

图片

图上的关系

点与点——邻接

在无向图 𝐺=(𝑉,𝐸)G=(V,E) 中,对于两顶点 𝑢u 和 𝑣v ,若存在边 (𝑢,𝑣)(u,v) ,则称 𝑢u 和 𝑣v 是 相邻(邻接)的 。

一个顶点 𝑣∈𝑉v∈V 的 邻域 (Neighborhood) 是所有与之相邻的顶点所构成的集合,记作 𝑁(𝑣)N(v) 。

PS:邻接表存储的就是邻域,并且由此得名。

点与边——关联

在无向图 𝐺=(𝑉,𝐸)G=(V,E) 中,若点 𝑣v 是边 𝑒e 的一个端点,则称 𝑣v 和 𝑒e 是 关联的

度数

与一个顶点 𝑣v 关联的边的条数称作该顶点的 度 (Degree) ,记作 𝑑(𝑣)d(v) 。特别地,对于边 (𝑣,𝑣)(v,v) ,则每条这样的边要对 𝑑(𝑣)d(v) 产生 22 的贡献。

对于无向简单图,有 𝑑(𝑣)=∣𝑁(𝑣)∣d(v)=∣N(v)∣ 。

握手定理(又称图论基本定理):对于任何无向图 𝐺=(𝑉,𝐸)G=(V,E) ,有 ∑𝑣∈𝑉𝑑(𝑣)=2∣𝐸∣∑v∈V​d(v)=2∣E∣ ,即无向图中结点度数的总和等于边数的两倍。有向图中结点的入度之和等于出度之和等于边数。

推论: 在任意图中,度数为奇数的点必然有偶数个。

证明:反证法

简单图

自环 (Loop) :对 𝐸E 中的边 𝑒=(𝑢,𝑣)e=(u,v) ,若 𝑢=𝑣u=v ,则 𝑒e 被称作一个自环。

重边/平行边 (Multiple edge) :若 𝐸E 中存在两个完全相同的元素(边) 𝑒1,𝑒2e1​,e2​ ,则它们被称作(一组)重边。

简单图 (Simple graph) :若一个图中 没有自环和重边,它被称为简单图。非空简单无向图中一定存在度相同的结点。

如果一张图中有自环或重边,则称它为 多重图 (Multigraph) 。

图片

​ 在无向图中 (𝑢,𝑣)(u,v) 和 (𝑣,𝑢)(v,u) 算一组重边,而在有向图中, 𝑢→𝑣u→v 和 𝑣→𝑢v→u 不为重边。

​ 在题目中,如果没有特殊说明,是可以存在自环和重边的,在做题时需特殊考虑。

路径

途径 (Walk) / 链 (Chain) :一个点和边的交错序列,其中首尾是点—— 𝑣0,𝑒1,𝑣1,𝑒2,𝑣2,…,𝑒𝑘,𝑣𝑘v0​,e1​,v1​,e2​,v2​,…,ek​,vk​ ,有时简写为 𝑣0→𝑣1→𝑣2→⋯→𝑣𝑘v0​→v1​→v2​→⋯→vk​ 。其中 𝑒𝑖ei​ 的两个端点分别为 𝑣𝑖−1vi−1​ 和 𝑣𝑖vi​ 。通常来说,边的数量 𝑘k 被称作这条途径的 长度 (如果边是带权的,长度通常指路径上的边权之和,题目中也可能另有定义)。(以下设 𝑤=[𝑣0,𝑒1,𝑣1,𝑒2,𝑣2,⋯,𝑒𝑘,𝑣𝑘]w=[v0​,e1​,v1​,e2​,v2​,⋯,ek​,vk​] 。)

迹 (Trail) :对于一条途径 𝑤w ,若 𝑒1,𝑒2,⋯,𝑒𝑘e1​,e2​,⋯,ek​ 两两互不相同,则称 𝑤w 是一条迹。

路径 (Path) (又称 简单路径 (Simple path) ):对于一条迹 𝑤w ,除了 𝑣0v0​ 和 𝑣𝑘vk​ 允许相同外,其余点两两互不相同,则称 𝑤w 是一条路径。

回路 (Circuit) :对于一个迹 𝑤w ,若 𝑣0=𝑣𝑘v0​=vk​ ,则称 𝑤w 是一个回路。

环/圈 (Cycle) (又称 简单回路/简单环 (Simple circuit) ):对于一条简单路径 𝑤w ,若 𝑣0=𝑣𝑘v0​=vk​ ,则称 𝑤w 是一个环。

!!! warning
关于路径的定义在不同地方可能有所不同,如,“路径”可能指本文中的“途径”,“环”可能指本文中的“回路”。如果在题目中看到类似的词汇,且没有“简单路径”/“非简单路径”(即本文中的“途径”)等特殊说明,最好询问一下具体指什么。

连通

无向图

对于一张无向图 𝐺=(𝑉,𝐸)G=(V,E) ,对于 𝑢,𝑣∈𝑉u,v∈V ,若存在一条途径使得 𝑣0=𝑢,𝑣𝑘=𝑣v0​=u,vk​=v ,则称 𝑢u 和 𝑣v 是 连通的 (Connected) 。由定义,任意一个顶点和自身连通,任意一条边的两个端点连通。

若无向图 𝐺=(𝑉,𝐸)G=(V,E) ,满足其中任意两个顶点均连通,则称 𝐺G 是 连通图 (Connected graph) , 𝐺G 的这一性质称作 连通性 (Connectivity) 。

若 𝐻H 是 𝐺G 的一个连通子图,且不存在 𝐹F 满足 𝐻⊊𝐹⊆𝐺H⊊F⊆G 且 𝐹F 为连通图,则 𝐻H 是 𝐺G 的一个 连通块/连通分量 (Connected component) (极大连通子图)。

图片

图片

有向图

对于一张有向图 𝐺=(𝑉,𝐸)G=(V,E) ,对于 𝑢,𝑣∈𝑉u,v∈V ,若存在一条途径使得 𝑣0=𝑢,𝑣𝑘=𝑣v0​=u,vk​=v ,则称 𝑢u 可达 𝑣v 。由定义,任意一个顶点可达自身,任意一条边的起点可达终点。(无向图中的连通也可以视作双向可达。)

若一张有向图的节点两两互相可达,则称这张图是 强连通的 (Strongly connected) 。

图片

若一张有向图的边替换为无向边后可以得到一张连通图,则称原来这张有向图是 弱连通的 (Weakly connected) 。

与连通分量类似,也有 弱连通分量 (Weakly connected component) (极大弱连通子图)和 强连通分量 (Strongly Connected component) (极大强连通子图)。

图片

𝑛n 个顶点的强连通图最多 𝑛(𝑛−1)n(n−1) 条边,最少 𝑛n 条边。

图片

图的连通性也是竞赛的一个常见考点,相关算法请后面将学习,现在先理解其概念即可。

稀疏图/稠密图

若一张图的边数远小于其点数的平方,那么它是一张 稀疏图 (Sparse graph) 。

若一张图的边数接近其点数的平方,那么它是一张 稠密图 (Dense graph) 。

这两个概念并没有严格的定义,一般用于讨论 时间复杂度 为 𝑂(∣𝑉∣2)O(∣V∣2) 的算法与 𝑂(∣𝐸∣)O(∣E∣) 的算法的效率差异(在稠密图上这两种算法效率相当,而在稀疏图上 𝑂(∣𝐸∣)O(∣E∣) 的算法效率明显更高)。

特殊的图

完全图

若无向简单图 𝐺G 满足任意不同两点间均有边,则称 𝐺G 为 完全图 (Complete graph) , 𝑛n 阶完全图记作 𝐾𝑛Kn​ 。若有向图 𝐺G 满足任意不同两点间都有两条方向不同的边,则称 𝐺G 为 有向完全图 (Complete digraph) 。

图片

环图/圈图

若无向简单图 𝐺=(𝑉,𝐸)G=(V,E) 的所有边恰好构成一个圈,则称 𝐺G 为 环图/圈图 (Cycle graph) , 𝑛n ( 𝑛≥3n≥3 ) 阶圈图记作 𝐶𝑛Cn​ 。易知,一张图为圈图的充分必要条件是,它是 22 - 正则连通图。

星图/菊花图

若无向简单图 𝐺=(𝑉,𝐸)G=(V,E) 满足,存在一个点 𝑣v 为支配点,其余点之间没有边相连,则称 𝐺G 为 星图/菊花图 (Star graph) , 𝑛+1n+1 ( 𝑛≥1n≥1 ) 阶星图记作 𝑆𝑛Sn​ 。

轮图

若无向简单图 𝐺=(𝑉,𝐸)G=(V,E) 满足,存在一个点 𝑣v 为支配点,其它点之间构成一个圈,则称 𝐺G 为 轮图 (Wheel Graph) , 𝑛+1n+1 ( 𝑛≥3n≥3 ) 阶轮图记作 𝑊𝑛Wn​ 。

image-20210328095407460

若无向简单图 𝐺=(𝑉,𝐸)G=(V,E) 的所有边恰好构成一条简单路径,则称 𝐺G 为 链 (Chain/Path Graph) , 𝑛n 阶的链记作 𝑃𝑛Pn​ 。易知,一条链由一个圈图删去一条边而得。

如果一张无向连通图不含环,则称它是一棵 树 (Tree) 。相关内容详见 树基础 。

补图

对于无向简单图 𝐺=(𝑉,𝐸)G=(V,E) ,它的 补图 (Complement graph) 指的是这样的一张图:记作 𝐺ˉGˉ ,满足 𝑉(𝐺ˉ)=𝑉(𝐺)V(Gˉ)=V(G) ,且对任意节点对 (𝑢,𝑣)(u,v) , (𝑢,𝑣)∈𝐸(𝐺ˉ)(u,v)∈E(Gˉ) 当且仅当 (𝑢,𝑣)∉𝐸(𝐺)(u,v)∈/E(G) 。

图片

反图

对于有向图 𝐺=(𝑉,𝐸)G=(V,E) ,它的 反图 (Transpose Graph) 指的是点集不变,每条边反向得到的图,即:若 𝐺G 的反图为 𝐺′=(𝑉,𝐸′)G′=(V,E′) ,则 𝐸′={(𝑣,𝑢)∣(𝑢,𝑣)∈𝐸}E′={(v,u)∣(u,v)∈E} 。

平面图

如果一张图可以画在一个平面上,且没有两条边在非端点处相交,那么这张图是一张 平面图 (Planar graph) 。一张图的任何子图都不是 𝐾5K5​ 或 𝐾3,3K3,3​ 是其为一张平面图的充要条件。对于简单连通平面图 𝐺=(𝑉,𝐸)G=(V,E) 且 𝑉≥3V≥3 , ∣𝐸∣≤3∣𝑉∣−6∣E∣≤3∣V∣−6 。

image-20210328095019950

 

学习目标

  • 掌握图的四种存储方法的代码实现
  • 理解图的四种存储方法各自的时间空间复杂度
  • 能够根据题目的要求和数据范围,选择合适存图方式

图的逻辑结构

一张图是由节点构成的,一个无向图如下图所示:

图片

什么叫 「逻辑结构」?就是说为了方便研究,我们把图 抽象 成这个样子。

根据这个逻辑结构,我们可以认为每个节点的实现如下:

// 图节点的逻辑结构
struct node {
    int data;                 // 存当前结点信息
    vector<int> neighbors;  // 存邻接的所有结点
}

看到这个实现,你有没有很熟悉?它和我们之前说的多叉树节点几乎完全一样:

// 树节点的逻辑结构
struct node {
    int data;                 // 存当前结点信息
    vector<int> son;        // 存所有的子结点
}

Copy

不过呢,上面的这种实现是「逻辑上的」,实际上我们很少用这个node类实现图,而是用接下来介绍的几种方法去存储。其中包含我们前面经常提到的 邻接表和邻接矩阵

图的存储方法

接下来描述图的具体四种存储方式,这四种方式是我们今后和图这种数据结构打交道的接口,请一定要掌握。

首先约定,用 𝑛n 代指图的点数,用 𝑚m 代指图的边数,用 𝑑+(𝑢)d+(u) 代指点 𝑢u 的出度,即以 𝑢u 为出发点的边数。

直接存边

方法

使用一个数组来存边,数组中的每个元素都包含一条边的起点与终点(带边权的图还包含边权)。(或者使用多个数组分别存起点,终点和边权。)

#include <iostream>
#include <vector>
using namespace std;

struct Edge {
    int u, v, w;   // 一条边的 起点、终点、权值
};

int n, m;
vector<Edge> e;
vector<bool> vis;

// 函数功能:判断 u,v 之间有没有边
bool find_edge(int u, int v) {
    for (int i = 1; i <= m; ++i) {
        if (e[i].u == u && e[i].v == v) {
            return true;
        }
    }
    return false;
}

// 遍历图
void dfs(int u) {
    if (vis[u]) return;
    vis[u] = true;
    for (int i = 1; i <= m; ++i) {
        if (e[i].u == u) {
            dfs(e[i].v);
        }
    }
}

int main() {
  cin >> n >> m;
  // 初始化 vector 数组,也可以将 vis 定义成: “bool vis[N];” 以省去初始化。下同
  vis.resize(n + 1, false);
  e.resize(m + 1);

  for (int i = 1; i <= m; ++i) cin >> e[i].u >> e[i].v >> e[i].w;

  return 0;
}

复杂度

查询是否存在某条边: 𝑂(𝑚)O(m) 。

遍历一个点的所有出边: 𝑂(𝑚)O(m) 。

遍历整张图: 𝑂(𝑛𝑚)O(nm) 。

空间复杂度: 𝑂(𝑚)O(m) 。

应用

由于直接存边的遍历效率低下,一般不用于遍历图。

在 Kruskal 算法中,由于需要将边按边权排序,需要直接存边。

在有的题目中,需要多次建图(如建一遍原图,建一遍反图),此时既可以使用多个其它数据结构来同时存储多张图,也可以将边直接存下来,需要重新建图时利用直接存下的边来建图。

邻接矩阵

方法

使用一个二维数组 g 来存边,其中 g[u][v] 为 1 表示存在 𝑢u 到 𝑣v 的边,为 0 表示不存在。

如果是带边权的图,可以在 g[u][v] 中存储 𝑢u 到 𝑣v 的边的边权,0 表示没有连接,其他值表示权重。

如果是无向图,则将一条无向边拆成两条方向相反的边即可。(所谓的「无向」,也就等同于「双向」)

#include <iostream>
#include <vector>
using namespace std;

const int N = 1e5+5;
int n, m;
bool vis[N];
bool g[N][N];

bool find_edge(int u, int v) { return g[u][v]; }

void dfs(int u) {
    if (vis[u]) return;
    vis[u] = true;
    for (int v = 1; v <= n; ++v) {
        if (g[u][v]) {
            dfs(v);
        }
    }
}

int main() {
    cin >> n >> m;

    fill_n(vis, N, false);  // 将 vis 数组清 false,类似 memset
    fill_n(g, N*N, false);
    
    for (int i = 1; i <= m; ++i) {
        int u, v;
        cin >> u >> v;
        g[u][v] = true;   // u->v 有条单向边
        // 如果是双向边
        // g[u][v] = g[v][u] = true;
    }
    return 0;
}

复杂度

查询是否存在某条边: 𝑂(1)O(1) 。

遍历一个点的所有出边: 𝑂(𝑛)O(n) 。

遍历整张图: 𝑂(𝑛2)O(n2) 。

空间复杂度: 𝑂(𝑛2)O(n2) 。

应用

邻接矩阵只适用于没有重边(或重边可以忽略)的情况。

其最显著的优点是可以 𝑂(1)O(1) 查询一条边是否存在。

由于邻接矩阵在稀疏图上效率很低(尤其是在点数较多的图上,空间无法承受),所以一般只会 在稠密图上使用邻接矩阵。并且,在稠密图上使用邻接矩阵的运行效率远高于邻接表,这是因为 CPU 中顺序访问的速度是远高于随机访问的(缓存命中)。

图片

邻接表

方法

使用一个支持动态增加元素的数据结构构成的数组,如 vector<int> g[N] 来存边,其中 g[u] 存储的是点 𝑢u 的所有出边的相关信息(终点、边权等)。

#include <iostream>
#include <vector>
using namespace std;

const int N = 1e5+5;
int n, m;
bool vis[N];
vector<int> g[N];

bool find_edge(int u, int v) {
    for (int i = 0; i < g[u].size(); ++i) {
        if (g[u][i] == v) {
            return true;
        }
    }
    return false;
}

void dfs(int u) {
    if (vis[u]) return;
    vis[u] = true;
    for (int i = 0; i < g[u].size(); ++i) dfs(g[u][i]);
}

int main() {
    cin >> n >> m;
    
    vis.resize(n + 1, false);
    g.resize(n + 1);
    
    for (int i = 1; i <= m; ++i) {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        // 如果是无向图,还须:
        // g[v].push_back(u);
    }
    
    return 0;
}

复杂度

查询是否存在 𝑢u 到 𝑣v 的边: 𝑂(𝑑+(𝑢))O(d+(u)) (如果事先进行了排序就可以使用 二分查找 做到 𝑂(log⁡(𝑑+(𝑢)))O(log(d+(u))) )。

遍历点 𝑢u 的所有出边: 𝑂(𝑑+(𝑢))O(d+(u)) 。

遍历整张图: 𝑂(𝑛+𝑚)O(n+m) 。

空间复杂度: 𝑂(𝑚)O(m) 。

应用

存各种图都很适合,除非有特殊需求(如需要快速查询一条边是否存在,且点数较少,可以使用邻接矩阵)。

尤其适用于需要对一个点的所有出边进行排序的场合。

链式前向星

方法

本质上是用链表实现的邻接表,示例代码如下:

#include <iostream>
#include <vector>
using namespace std;

const int N = 1e5+5;
int n, m;

bool vis[N];
int head[N], nxt[N], to[N], cnt;     // 链式前向星三要素

void add(int u, int v) {     // 添加一条 u->v 的边
    nxt[++cnt] = head[u];    // cnt 这条边的后继(同是 u 的出边的上一条边)
    to[cnt] = v;             // 当前边的终点是 v
    head[u] = cnt;           // 起点 u 的第一条边放到了下标 cnt 处(其实是最后一条)
}

bool find_edge(int u, int v) {
  for (int i = head[u]; ~i; i = nxt[i]) {  // ~i 表示 i != -1
    if (to[i] == v) {
        return true;
    }
  }
  return false;
}

void dfs(int u) {
    if (vis[u]) return;
    vis[u] = true;
    cout << u << ' ';
    for (int i = head[u]; ~i; i = nxt[i])
        dfs(to[i]);
}

int main() {
    cin >> n >> m;
    
    fill_n(vis, N, false);
    fill_n(head, N, -1);
    
    for (int i = 1; i <= m; ++i) {
        int u, v;
        cin >> u >> v;
        add(u, v);
    }
    dfs(1);
    return 0;
}

如果图是赋权图,即边带有权重时,此时数组定义过多,也可以写成结构体去保存,参考代码如下:

#include<bits/stdc++.h>
using namespace std;

const int N = 1e5;    //点数最大值
int n, m;             //n个点,m条边
int head[N], cnt = -1;     //head[i],表示以i为起点的第一条边在边集数组的位置(编号)

struct Edge
{
    int to, w, next;   // 终点,边权,同起点的上一条边的编号
}edge[N];//边集

void add_edge(int u, int v, int w)// 加边,u 起点,v 终点,w 边权
{
    edge[++cnt].next = head[u];    // 以u为起点上一条边的编号,也就是与这个边起点相同的上一条边的编号
    edge[cnt].to = v;          // 终点
    edge[cnt].w = w;             // 权值
    head[u] = cnt;               // 更新以u为起点上一条边的编号
}
int main()
{
    cin >> n >> m;
    int u, v, w;
    fill_n(head, N, -1);
    
    for (int i = 1; i <= m; i++) // 输入m条边
    {
        cin >> u >> v >> w;
        add_edge(u, v, w);       // 加边
        // 加双向边
        // add_edge(u, v, w);
        // add_edge(v, u, w);
    }
    // 输出每个结点的出边
    for (int i = 1; i <= n; i++)
    {
        cout << i << endl;
        for (int j = head[i]; ~j; j = edge[j].next)  // 遍历以 i为起点的边
        {
            cout << i << " " << edge[j].to << " " << edge[j].w << endl;
        }
        cout << endl;
    }
    return 0;
}
/*
5 7
1 2 1
2 3 2
3 4 3
1 3 4
4 1 5
1 5 6
4 5 7
*/

复杂度

查询是否存在 𝑢u 到 𝑣v 的边: 𝑂(𝑑+(𝑢))O(d+(u)) 。

遍历点 𝑢u 的所有出边: 𝑂(𝑑+(𝑢))O(d+(u)) 。

遍历整张图: 𝑂(𝑛+𝑚)O(n+m) 。

空间复杂度: 𝑂(𝑚)O(m) 。

应用

注意:利用链式前向星遍历的边的顺序和输入顺序是相反的!

存各种图都很适合,但是缺点也很明显, 不能快速查询一条边是否存在,也不能方便地对一个点的出边进行排序

优点是边是带编号的,有时会非常有用,而且如果边是从数组的偶数位开始存储( 按上面示例代码写法是从 0 开始存储的,cnt 的初始值为 -1),存双向边时 i ^ 1 即是 i 的反边(常用于网络流 )。

总结

图的存储方法比较多,每种方法各有优缺点,对比如下:

直接存边邻接矩阵邻接表链式前向星
使用场合需要将边按边权排序时;需要重新建图时利用直接存下的边来建图只适用于没有重边(或重边可以忽略)的情况;可以 𝑂(1)O(1) 查询边;在稠密图上效率很高消耗空间较小,各种场合都适用,尤其适用于需要对点的出边排序的场合消耗空间小,各种场合都适用
缺点遍历效率低下,一般不用于遍历图只适用于没有重边(或重边可以忽略)的情况。需熟练掌握 vector 操作?不能迅速查询边和对一个点的出边排序

总的来说,就是:

  1. 需要对所有边进行排序时,直接存边;
  2. 图很稠密,用邻接矩阵;
  3. 其他一般情况,用邻接表或链式前向星都可以。

请在理解各种方法的优缺点并掌握其代码实现以后,面对具体问题应思考选择合适的方法。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

绝地求生:经典艾伦格即将回归!绝地求生艾伦格进化史

29.2版本经典艾伦格地图将会回归&#xff0c;让我回顾一下艾伦格地图的改动历史吧&#xff01; 回归时间 2016年早期A测 A测 4.1版本&#xff1a;艾伦格-新视界 主要区域变动 Military Base(军事基地) Military Base Mylta Power&#xff08;大电&#xff09; Mylta Power …

Adobe After Effects AE v24.3.0 解锁版 (视频合成及视频特效制作)

Adobe系列软件安装目录 一、Adobe Photoshop PS 25.6.0 解锁版 (最流行的图像设计软件) 二、Adobe Media Encoder ME v24.3.0 解锁版 (视频和音频编码渲染工具) 三、Adobe Premiere Pro v24.3.0 解锁版 (领先的视频编辑软件) 四、Adobe After Effects AE v24.3.0 解锁版 (视…

笔记:完善python selenium 讯飞写作的整体自动化

昨天做得不太好,今天再来一次,我发现,只要写得多,一定会有发现。 1、加入本地目录,不要一直登录。 # 定义Edge浏览器的用户数据目录edge_user_data_dir = r"C:\Users\Administrator\AppData\Local\Microsoft\Edge\User Data\Default"# 设置Edge选项edge_optio…

解锁AI写作新纪元的文心一言指令

解锁AI写作新纪元的文心一言指令 在人工智能&#xff08;AI&#xff09;飞速发展的今天&#xff0c;自然语言处理&#xff08;NLP&#xff09;技术取得了显著的进步。文心一言&#xff0c;作为NLP领域的一颗璀璨明星&#xff0c;以其强大的文本生成和指令理解能力&#xff0c;为…

广东省网络安全竞赛部分web,misc wp

我的队伍只做了5题&#xff0c;还是太菜了&#xff0c;本来不想发的&#xff0c;但是写都写了&#xff0c;还是水一篇博客吧 这里是我们队的wp misc1 给了一个压缩包&#xff0c;解压需要密码&#xff0c;用纯数字密码没跑出来&#xff0c;感觉可能不是要强跑&#xff0c;看…

UIKit常用API:Transform

需求 使用Transform系列的API&#xff0c;该API中提供了旋转、平移等功能。其中函数中带make的效果是只变化一次&#xff0c;不带make可变化多次。此外&#xff0c;还有恢复函数&#xff1a;CGAffineTransformIdentity。 代码实现 注意按钮绑定的是同一个响应事件&#xff0…

详细分清Session,Cookie和Token之间的区别,以及JWT是什么东西

Cookie Cookie是一种小型的文本文件&#xff0c;由网站在用户访问时存储在其计算机或移动设备上&#xff0c;Cookie主要用于跟踪、识别和存储有关用户的信息。 简单来说Cookie就是用来存储某些后端发送给前端的数据&#xff0c;例如我们登陆后&#xff0c;后端会返回一个登录…

PythonStudio 控件使用常用方式(十一)MessageBox

PythonStudio是一个极强的开发Python的IDE工具&#xff0c;它使用的是Delphi的控件&#xff0c;常用的内容是与Delphi一致的。但是相关文档并一定完整。现在我试试能否逐步把它的控件常用用法写一点点&#xff0c;也作为PythonStudio的参考。 MessageBox是一个消息对话框&…

AI图书推荐:ChatGPT等生成式AI在高等教育中的应用

自2022年11月以来&#xff0c;ChatGPT及其在高等教育各个层面的影响已成为所有教育对话的核心内容。Chan和Colloton所著的书籍是首批全面探讨ChatGPT与生成式人工智能&#xff08;GenAI&#xff09;在高等教育中应用及影响的作品之一。 该书深入研究了针对专业环境定制的AI素养…

CHATGLM3应用指南(三)——模型微调

CHATGLM3的本地部署可以见博客&#xff1a;CHATGLM3应用指南&#xff08;一&#xff09;——本地部署_chatglm3需要多大内存-CSDN博客 一、微调数据集制作 数据集的形式如下图所示&#xff1a; 可使用下面代码对数据集格式调整 #! /usr/bin/env python print(!!!!!) import …

AI办公自动化-用kimi自动清理删除重复文件

在kimichat中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个编写Python脚本的任务&#xff0c;具体步骤如下&#xff1a; 1、打开文件夹D:\downloads&#xff1b; 2、哈希值比较比较里面所有的文件&#xff0c;如果文件相同&#xff0c;那么移动多余…

秒杀系统之设计方向

1 秒杀存在的问题 对于一个日常平稳的业务系统&#xff0c;如果直接开通秒杀功能的话&#xff0c;往往会出现很多问题—— 2 设计方向的思考 秒杀本质是要求一个瞬时高发下的承压系统&#xff0c;这也是其区别于其他业务的核心场景。对日常系统秒杀产生的问题逐一进行拆解分…

MPLAB X IDE编译attiny1616工程报错却无报错信息

MPLAB X IDE(XC-8编译器)编译报错&#xff0c;无具体错误内容&#xff0c;仅显示需要xc-8 pro的警告。 内存占用率显示为81%&#xff0c;未超标。 原因&#xff1a;软件使用了microchip的bootloader功能。应用程序起始地址&#xff08;也是bootloader结束地址&#xff09;设置错…

【SAP ABAP学习资料】通过RFC接口上传图片至SAP 图片格式转换 图片大小调整

SAP图片相关&#xff1a; 链接: 【SAP ABAP学习资料】图片上传SAP 链接: 【SAP ABAP学习资料】屏幕图片预览 链接: 【SAP ABAP学习资料】smartforms打印图片&#xff0c;动态打印图片 需求&#xff1a; SAP上传图片只能本地电脑选择图片通过SE78或PERFORM IMPORT_BITMAP_BDS上…

【专利】一种日志快速分析方法、设备、存储介质

公开号CN116560938A申请号CN202310311478.5申请日2023.03.28 是我在超音速人工智能科技股份有限公司(833753) 职务作品&#xff0c;第一发明人是董事长夫妇&#xff0c;第二发明人是我。 ** 注意** &#xff1a; 内容比较多&#xff0c;还有流程图、界面等。请到 专利指定页面…

SSL/TLS协议信息泄露漏洞(CVE-2016-2183)解法

1.运行gpedit.msc&#xff0c;进入本地组策略编辑器。 2. 本地组策略编辑器-->计算机配置-->管理模板-->网络-->SSL配置设置-->启用“SSL密码套件顺序”。 3. 将原有的密码套件值清空&#xff0c;拷入下面的值&#xff0c;保存设置&#xff0c;并重启服务器即…

AI时代的网络安全战:以智取胜,守护数字安宁

在数字化浪潮的推动下&#xff0c;我们的生活和工作日益离不开互联网。然而&#xff0c;随着人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;网络安全问题也日益凸显。美国联邦调查局&#xff08;FBI&#xff09;的一则警报如同一记重锤&#xff0c;敲响了我们对…

CANopen NWT,SDO,HeartBeat报文协议

什么是CANopen&#xff1f; CANopen是一个基于CAN总线的“高层协议”&#xff0c;这意味着CAN总线&#xff08;ISO 11898&#xff09;就像集装箱的卡车一般作为CANopen信息的“运输工具”。 CAN只是实现了带有11位CAN ID、远程传输&#xff08;RTR&#xff09;位和64个数据位&…

【VUE.js】前端框架——未完成

基于脚手架创建前端工程 环境 当安装node.js时&#xff0c;它本身就携带有npm命令。&#xff08;-v 查版本号&#xff09;安装VUE CLI npm i vue/cli -g&#xff08;全局&#xff09; 创建 vue create 【project name】 镜像源解决方案 输入创建命令后&#xff0c;提示检查更…

论文阅读记录--关于水文系统的传递函数

文章目录 J-schuite的文章,地下水系统的响应的功率谱分析--传递函数1. 什么是冲激响应函数与传递函数?2. 地下水流系统中传递函数的求解3. J-schuite文章中传递函数的复现J-schuite的文章,地下水系统的响应的功率谱分析–传递函数 1. 什么是冲激响应函数与传递函数? 在信号…