常用算法代码模板 (3) :搜索与图论

news2024/11/26 16:47:17

AcWing算法基础课笔记与常用算法模板 (3) ——搜索与图论

常用算法代码模板 (1) :基础算法
常用算法代码模板 (2) :数据结构
常用算法代码模板 (3) :搜索与图论
常用算法代码模板 (4) :数学知识

文章目录

  • 0 搜索技巧
  • 1 树与图的存储
    • 1.1 邻接矩阵
    • 1.2 邻接表
  • 2 树与图的遍历
    • 2.1 深度优先遍历
    • 2.2 宽度优先遍历
  • 3 拓扑排序
  • 4 最短路径
    • 4.1 朴素Dijkstra算法
    • 4.2 堆优化Dijkstra算法
    • 4.3 Bellman-Ford算法
    • 4.4 SPFA算法
    • 4.5 Floyd算法
  • 5 最小生成树
    • 5.1 朴素版Prim算法
    • 5.2 Kruskal算法
  • 6 二分图
    • 6.1 染色法
    • 6.2 匈牙利算法


0 搜索技巧

  • DFS
    • 分析问题:画图归纳
    • 保存现场
    • 剪枝
  • BFS
    • 必要时开距离数组记录 <u>第一次 </u>到达每个点时的距离(即为到达每个点的最短路距离)

偏移量

控制点在二维平面上移动的方向(搜索方向),可设定方向下标按顺时针()递增。此时对于方向下标 i,其反方向下标为 i ^ 2(对2做按位异或运算),也可手动if设置求得。

int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};	// 上(-1, 0),右(0, 1),下(1, 0),左(0, -1)

1 树与图的存储

1.1 邻接矩阵

注意无法存储重边

int g[N][N];	// g[a][b]存储有向边<a, b>

/* 初始化 */
memset(g, 0x3f, sizeof g);

1.2 邻接表

const int N = 1e5, M = 2 * N;
  
int n, m;	// 点数、边数
int h[N], e[M], ne[M], idx;	// h[k]为点k的边表的头指针

/* 初始化 */
memset(h, -1, sizeof h);
idx = 0;

/* 添加一条边<a, b> */
void add(int a, int b) {
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

2 树与图的遍历

时间复杂度: O ( n + m ) O(n+m) O(n+m)

2.1 深度优先遍历

bool st[N];

int dfs(int u) {
    st[u] = true;
  
    for (int i = h[u]; ~i; i = ne[i]) {	// 遍历u的所有出边
        int v = e[i];
        if (!st[v]) dfs(v);
    }
}

2.2 宽度优先遍历

bool st[N];	// V: [1 ... n]

void bfs() {
    queue<int> q;
    q.push(1);	// 队中压入初值
    st[1] = true;

    while (!q.empty()) {
        int t = q.front();
        q.pop();

        for (int i = h[t]; ~i; i = ne[i]) {	// 遍历点t的所有出边
            int u = e[i];
            if (!st[u]) {
                st[u] = true;
                q.push(u);
            }
        }
    }
}

3 拓扑排序

时间复杂度: O ( n + m ) O(n+m) O(n+m)

int n;		// V: [1 ... n]
int q[N], hh = 0, tt = -1;	// 顶点队列,存储拓扑序列
int d[N];	// d[i]存储点i的入度

/* 拓扑排序:将拓扑序列存在队列中 */
bool topsort() {
    for (int i = 1; i <= n; i++)	// 将所有度为0的点入队
        if (d[i] == 0) q[++tt] = i;
  
    while (hh <= tt) {
        int t = q[hh++];
  
        for (int i = h[t]; ~i; i = ne[i]) {	// 遍历点t的所有出边
            int u = e[i];	// 该出边对应的点u
            if (--d[u] == 0) q[++tt] = u;	// 删去该出边并判定:u入度变为0了则入队
        }
    }
  
    return tt = n - 1;	// 如果所有点都入队了,说明存在拓扑序列;否则不存在拓扑序列
}

/* 输出拓扑序列(若存在) */
if (topsort()) {
    for (int i = 0; i < n; i++) printf("%d ", q[i]);
    puts("");
}

4 最短路径

4.1 朴素Dijkstra算法

时间复杂度: O ( n 2 + m ) O(n^2+m) O(n2+m)

适用情形:稠密图

int n;			// V: [1 ... n]
int g[N][N];	// 邻接矩阵图(带权)
int dist[N];	// dist[]存储起点到每个点的最短路径
bool st[N];		// st[]标记每个点的最短路是否已被确定

/* 求起点S到终点T的最短路,若不存在则返回-1 */
int dijkstra(int S, int T) {
    memset(dist, 0x3f, sizeof dist);
    dist[S] = 0;	// 这里只先设起点的dist
  
    for (int i = 0; i < n; i++) {	// 迭代n次(第1轮预处理起点)
        int t = -1;	// 在还未确定最短路的点中,寻找最短距离点t
        for (int j = 1; j <= n; j++)
            if (!st[j] && (t == -1 || dist[t] > dist[j])) 
                t = j;
  
        st[t] = true;
  
        for (int j = 1; j <= n; j++)	// 用t更新其他点的距离
            if (dist[j] > dist[t] + g[t][j])
                dist[j] = dist[t] + g[t][j];
    }
  
    if (dist[T] == 0x3f3f3f3f) return -1;
    return dist[T];
}

4.2 堆优化Dijkstra算法

时间复杂度: O ( m log ⁡ n ) O(m\log n) O(mlogn)

适用情形:稀疏图

typedef pair<int, int> PII;

int n;			// V: [1 ... n]
int h[N], e[M], w[M], ne[M], idx;	// 邻接表图,w[i]存边i的权值
int dist[N];	// dist[]存储起点到每个点的最短路径
bool st[N];		// st[]标记每个点的最短路是否已被确定

/* 求起点S到终点T的最短路,若不存在则返回-1 */
int dijkstra(int S, int T) {
    memset(dist, 0x3f, sizeof dist);
    dist[S] = 0;	// 这里也只先设起点的dist
  
    priority_queue<PII, vector<PII>, greater<PII> > heap;	// 堆(优先队列)
    heap.push({0, S});	// <distance, vertex>
  
    while (!heap.empty()) {
        auto t = heap.top();
        heap.pop();
        int u = t.second, distance = t.first;	// 用堆得到最近的点及与其距离
  
        if (st[u]) continue;	// 若已确定则跳过
        st[u] = true;
  
        for (int i = h[u]; ~i; i = ne[i]) {
            int v = e[i];
            if (dist[v] > distance + w[i]) {
                dist[v] = distance + w[i];
                heap.push({dist[v], v});
            }
        }
    }
  
    if (dist[T] == 0x3f3f3f3f) return -1;
    return dist[T];
}

4.3 Bellman-Ford算法

时间复杂度: O ( n m ) O(nm) O(nm)

适用情形:存在负权边的图

如果第 n n n 次迭代仍然会松弛三角不等式,就说明存在一条长度是 n + 1 n+1 n+1 的最短路径,由抽屉原理,路径中至少存在两个相同的点,说明图中存在负权回路(负环)。

int n, m;		// V: [1 ... n]
struct Edge {
    int a, b, w;
} edges[M];		// 边集,存储权值为w的有向边<a, b>
int dist[N];	// dist[]存储起点到每个点的最短路径

/* 求起点S到终点T的最短路,若不存在则返回-1 */
int bellman_ford(int S, int T) {
    memset(dist, 0x3f, sizeof dist);
    dist[S] = 0;
  
    for (int i = 0; i < n; i++) {	// 要求最大长度为n的最短路径,故迭代n次
        for (int j = 0; j < m; j++) {	// 每次遍历全部m条边
            int a = edges[j].a, b = edges[j].b, w = edges[j].w;
            if (dist[b] > dist[a] + w)	// 松弛操作:更新当前dist
                dist[b] = dist[a] + w;
        }
    }
  
    if (dist[T] > 0x3f3f3f3f / 2) return 0x3f3f3f3f;	// 因为负权边的存在,可能略低于INF
    return dist[T];
}

应用:求有边数限制的最短路

限制 k k k 条边就进行 k k k 轮迭代遍历,遍历开始前需先备份 dist[]backup[],用其将 dist[]更新。

int n, m, k;	// 限制最短路最多经过k条边
struct Edge {
    int a, b, w;
} edges[M];
int dist[N], backup[N];	// backup[]备份dist[]数组,防止发生串联(用改后数据去改别人)

/* 求起点S到终点T的最短路,若不存在则返回-1 */
int bellman_ford(int S, int T) {
    memset(dist, 0x3f, sizeof dist);
    dist[S] = 0;
  
    for (int i = 0; i < k; i++) {	// 限制k条边,则迭代k次
        memcpy(backup, dist, sizeof dist);	// 遍历边前先将dist拷贝至备份数组
        for (int j = 0; j < m; j++) {
            int a = edges[j].a, b = edges[j].b, w = edges[j].w;
            if (dist[b] > backup[a] + w)	// 使用备份数组做松弛操作
                dist[b] = backup[a] + w;
        }
    }
  
    if (dist[T] > 0x3f3f3f3f / 2) return 0x3f3f3f3f;
    return dist[T];
}

4.4 SPFA算法

时间复杂度:平均 O ( m ) O(m) O(m) ,最坏 O ( n m ) O(nm) O(nm)

队列优化的Bellman-Ford算法:后继变小了当前dist才变小

int n;			// V: [1 ... n]
int h[N], e[M], w[M], ne[M], idx;	// 邻接表图,w[i]存边i的权值
int dist[N];	// dist[]存储起点到每个点的最短路径
bool st[N];		// st[]标记每个点的最短路是否已被确定

int spfa(int S, int T) {
    memset(dist, 0x3f, sizeof dist);
    dist[S] = 0;
  
    queue<int> q;	// 队中存放待更新的点(用堆也行)
    q.push(S);
    st[S] = true;	// 结点入队时做标记
  
    while (!q.empty()) {	// 使用BFS的思想
        auto t = q.front();
        q.pop();
  
        st[t] = false;	// 结点出队时撤销标记(之后可能需再次入队被更新)
  
        for (int i = h[t]; ~i; i = ne[i]) {
            int u = e[i];
            if (dist[u] > dist[t] + w[i]) {
                dist[u] = dist[t] + w[i];
                if (!st[u]) {	// 若更新了u的距离,则其出边所指也可能待更新,判断将其入队
                    q.push(u);
                    st[u] = true;
                }
            }
        }
    }
  
    if (dist[T] == 0x3f3f3f3f) return 0x3f3f3f3f;
    return dist[T];
}

应用:SPFA判断图中是否存在负环

时间复杂度: O ( n m ) O(nm) O(nm)

不需要初始化 dist[],因此之后正权入边顶点永不会被更新;并且为消除某点可能无法到达负环的影响,将所有点全入队并标记!

原理:若某条最短路径上有 n n n 个点(除了自己),则加上自己之后一共有 n + 1 n+1 n+1 个点,由抽屉原理一定有两个点相同,所以存在负环。

int n;
int h[N], e[M], w[M], ne[M], idx;]
int dist[N], cnt[N];	// cnt[x]存储起点(任意)到x的最短路中经过的点数
bool st[N];

/* 如果存在负环,则返回true,否则返回false */
bool spfa() {
    queue<int> q;	// 不需要初始化dist数组,直接将所有点全入队并标记!
    for (int i = 1; i <= n; i++) {
        q.push(i);
        st[i] = true;
    }
  
    while (!q.empty()) {
        auto t = q.front();
        q.pop();
  
        st[t] = false;
  
        for (int i = h[t]; ~i; i = ne[i]) {
            int u = e[i];
            if (dist[u] > dist[t] + w[i]) {
                dist[u] = dist[t] + w[i];
                cnt[u] = cnt[t] + 1;	// 若更新了u的距离,则立即更新其cnt(前驱加1)
                if (cnt[u] >= n) return true;	// 若最短路已包含至少n个点(不含自身),则有负环
                if (!st[u]) {
                    q.push(u);
                    st[u] = true;
                }
            }
        }
    }
  
    return false;	// 跳出循环则说明无负环
}

4.5 Floyd算法

时间复杂度: O ( n 3 ) O(n^3) O(n3)

基于动态规划

int n;			// V: [1 ... n]
int d[N][N];	// 邻接矩阵图,经过Floyd()操作后变为存储最短距离

/* 初始化 */
for (int i = 1; i <= n; i++)
    for (int j = 1; j <= n; j++)
        if (i == j) d[i][j] = 0;
		else d[i][j] = INF;

/* 算法结束后,d[a][b]表示a到b的最短距离 */
void floyd() {
    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}

5 最小生成树

5.1 朴素版Prim算法

时间复杂度: O ( n 2 + m ) O(n^2+m) O(n2+m)

必须先累加 res再更新 dist[],以避免负自环污染当前 t最短距离

const int INF = 0x3f3f3f3f;

int n;			// V: [1 ... n]
int g[N][N];	// 邻接矩阵图
int dist[N];	// dist[]存储起点到当前最小生成树(MST)的最短距离
bool st[N];		// st[]标记每个点是否已经在生成树中

/* 若图不连通,则返回INF,否则返回最小生成树的最小代价 */
int prim() {
    memset(dist, 0x3f, sizeof dist);	// 仅计算最小代价,故无需另设起点
  
    int res = 0;	// 存储最小代价
    for (int i = 0; i < n; i++) {	// 迭代n次(第1轮预处理生成树根)
        int t = -1;	// 在还未并入MST的点中,寻找最短距离点t
        for (int j = 1; j <= n; j++)
            if (!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;
  
        if (i && dist[t] == INF) return INF;	// 从第2轮起,若最短距离为无穷,则说明不连通
        if (i) res += dist[t];	// 从第2轮起,将t的距离计入最小代价(须先累加res)
        st[t] = true;	// 将t并入MST
  
        for (int j = 1; j <= n; j++)	// 用新并入的t更新各点到生成树的距离
            if (dist[j] > g[t][j]) 	// 与dij不同,不应加前驱的dist(求取到整棵树的距离)
                dist[j] = g[t][j];
    }
  
    return res;
}

5.2 Kruskal算法

时间复杂度: O ( m log ⁡ m ) O(m\log m) O(mlogm)

int n, m;		// V: [1 ... n]
struct Edge {
    int a, b, w;
  
    bool operator<(const Edge &t) const {	// 重载运算符,用于按权递增排序
        return w < t.w;
    }
} edges[MAXM];	// 边集,存储权值为w的有向边<a, b>
int p[N];		// 并查集

/* 并查集核心操作 */
int find(int x) {
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

/* 若图不连通,则返回INF,否则返回最小生成树的最小代价 */
int kruskal() {
    sort(edges, edges + m);	// 将边按权递增排序(方式不限)
  
    for (int i = 1; i <= n; i++) p[i] = i;	// 初始化并查集
  
    int res = 0, cnt = 0;
    for (int i = 0; i < m; i++) {	// 枚举所有边,将合适的边并入MST(加入集合)
        int a = edges[i].a, b = edges[i].b, w = edges[i].w;
  
        a = find(a), b = find(b);
        if (a != b) {	// 如果两个连通块不连通,则将这两个连通块合并
            p[a] = b;
            res += w;
            cnt++;
        }
    }
  
    if (cnt < n - 1) return INF;	// 判定连通性(连通的必要条件:|E| = |V| - 1)
    return res;
}

6 二分图

在这里插入图片描述

定义:二分图可将图中顶点划分两个集合,使得集合内顶点互不邻接,不同集合顶点可邻接

定理:图为二分图 ⇔ \Leftrightarrow 图中不含奇数环

6.1 染色法

时间复杂度: O ( n + m ) O(n+m) O(n+m)

判断是否是二分图

思想:若为二分图,则与黑点相连的点均为白色,与白点相连的点均为黑色(邻接顶点不得同色)

int n;			// V: [1 ... n]
int h[N], e[M], ne[M], idx;	// 邻接表图
int color[N];	// 每个点的颜色:-1未染色,0白色,1黑色

/* 用dfs给结点u染颜色c,一切顺利返回true,出现冲突则返回false */
bool dfs(int u, int c) {
    color[u] = c;	// 给结点u染颜色c
  
    for (int i = h[u]; ~i; i = ne[i]) {	// 遍历所有从结点u指出的点
        int v = e[i];
        if (color[v] == -1) {	// 若v未染色则将其染与u相反的色(!c)并判定是否冲突
            if (!dfs(v, !c)) return false;
        } else if (color[v] == c) return false;	// 若v与u同色则出现冲突
    }
  
    return true;
}

/* 用染色法判断图是否是二分图 */
memset(color, -1, sizeof color);
bool success = true;
for (int i = 1; i <= n; i++)	// 遍历所有顶点,若未染色则染白色并判定是否冲突
    if (color[i] == -1)
        if (!dfs(i, 0)) {
            success = false;
            break;
        }

6.2 匈牙利算法

时间复杂度:最差 O ( n m ) O(nm) O(nm) ,实际运行时间一般远小于 O ( n m ) O(nm) O(nm)

用于求二分图的最大匹配数(匹配:某两个点有且只有他们之间有边,与别人无边)

匈牙利算法中只会用到从第1个集合指向第2个集合的边,所以这里只用存一个方向的边。

先欣赏y神讲解再看代码

int n1, n2;		// 二分图中两个集合的点数。集合1: [1 ... n1]、集合2: [1 ... n2]
int h[N], e[M], ne[M], idx;	// 邻接表图,只存集合1到集合2的边
int match[N];	// match[i] = j表示集合2的点i当前匹配集合1的点j(j=0表示暂无匹配)
bool st[N];		// st[i]标记集合2的点i是否已经被遍历过

/* 寻找与集合1的点u匹配集合2的点,返回是否成功 */
bool find(int u) {
    for (int i = h[u]; ~i; i = ne[i]) {	// "遍历所有可能的她"
        int v = e[i];
        if (!st[v]) {
            st[v] = true;
            if (match[v] == 0 || find(match[v])) {	// 判定"若她有则'去找他'"
                match[v] = u;	// 与她匹配
                return true;
            }
        }
    }
  
    return false;
}

/* 求最大匹配数 */
int res = 0;
for (int i = 1; i <= n1; i++) {	// 依次枚举集合1的每个点去匹配集合2的点
    memset(st, false, sizeof st);	// 每次重置遍历标记
    if (find(i)) res++;
}

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

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

相关文章

网络编程——TCP

socket socket类型 流式套接字(SOCK_STREAM) TCP 提供了一个面向连接、可靠的数据传输服务&#xff0c;数据无差错、无重复、无丢失、无失序的发送且按发送顺序接收。内设置流量控制&#xff0c;避免数据流淹没慢的接收方。数据被看作是字节流&#xff0c;无长度限制。 数据报…

学习STM32第二十天

低功耗编程 一、修改主频 STM32F4xx系列主频为168MHz&#xff0c;当板载8MHz晶振时&#xff0c;系统时钟HCLK满足公式 H C L K H S E P L L N P L L M P L L P HCLK \frac{HSE \times PLLN}{PLLM \times PLLP} HCLKPLLMPLLPHSEPLLN​&#xff0c;在文件stm32f4xx.h中可修…

寝室快修|基于SprinBoot+vue的贵工程寝室快修小程序(源码+数据库+文档)

贵工程寝室快修目录 目录 基于SprinBootvue的贵工程寝室快修小程序 一、前言 二、系统设计 三、系统功能设计 1学生信息管理 2 在线报修管理 3公告信息管理 4论坛信息管理 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&a…

基于SpringBoot+Vue校园竞赛管理系统的设计与实现

项目介绍&#xff1a; 传统信息的管理大部分依赖于管理人员的手工登记与管理&#xff0c;然而&#xff0c;随着近些年信息技术的迅猛发展&#xff0c;让许多比较老套的信息管理模式进行了更新迭代&#xff0c;竞赛信息因为其管理内容繁杂&#xff0c;管理数量繁多导致手工进行…

Android 学习 鸿蒙HarmonyOS 4.0 第二天(项目结构认识)

项目结构认识 和 了解&#xff1a; 工程目录下的结构如下&#xff1a; 首先能看到有两个.开头的文件&#xff0c;分别是.hvigor 和 .idea。这两个文件夹都是与构建有关系的&#xff0c; 如果你开发过安卓app&#xff0c;构建完会生成一个apk安装包&#xff0c;鸿蒙则是生成hap…

IDEA新版本创建Spring项目只能勾选17和21却无法使用Java8的完美解决方案

想创建一个springboot的项目&#xff0c;使用Spring Initializr创建项目时&#xff0c;发现版本只有17&#xff5e;21&#xff0c;无法选择Java8。 我们知道IDEA页面创建Spring项目&#xff0c;其实是访问spring initializr去创建项目。我们可以通过阿里云国服间接创建Spring项…

MATLAB 运算符

MATLAB 运算符 运算符是一个符号&#xff0c;告诉编译器执行特定的数学或逻辑操作。MATLAB设计为主要在整个矩阵和数组上运行。因此&#xff0c;MATLAB中的运算符既可以处理标量数据&#xff0c;也可以处理非标量数据。MATLAB允许以下类型的基本运算- 算术运算符 关系运算符…

拥抱数字化转型:电子招标系统平台的革新之路

随着信息技术的飞速发展&#xff0c;传统的采购和招标方式正逐渐被数字化解决方案所取代。电子招标系统平台作为这一转型的关键工具&#xff0c;正在全球范围内被越来越多的企业和政府机构所采纳。本文给大家简单介绍下电子招标系统平台的概念、优势以及如何选择一个合适的平台…

采用前后端分离Vue,Ant-Design技术开发的(手麻系统成品源码)适用于三甲医院

开发环境 技术架构&#xff1a;前后端分离 开发语言&#xff1a;C#.net6.0 开发工具&#xff1a;vs2022,vscode 前端框架&#xff1a;Vue,Ant-Design 后端框架&#xff1a;百小僧开源框架 数 据 库&#xff1a;sqlserver2019 系统特性 麻zui、护理、PACU等围术期业务全覆…

【实时数仓架构】方法论(未完)

笔者不是专业的实时数仓架构&#xff0c;这是笔者从其他人经验和网上资料整理而来&#xff0c;仅供参考。写此文章意义&#xff0c;加深对实时数仓理解。 一、实时数仓架构技术演进 1.1、四种架构演进 1&#xff09;离线大数据架构 一种批处理离线数据分析架构&#xff0c;通…

【大学生电子竞赛题目分析】——2023年H题《信号分离装置》

今年的大赛已临近落幕&#xff0c;笔者打算陆续对几个熟悉领域的题目作一番分析与讨论&#xff0c;今天首先分析H题。 网上有一些关于H题的分析&#xff0c;许多都是针对盲信号分析的。然而本题具有明确的信号频率范围&#xff0c;明确的信号可能频率&#xff0c;明确的信号波…

分布式与一致性协议之Paxos算法(三)

Paxos算法 兰伯特关于Multi-Paxos的思考 领导者 我们可以通过引入领导者(Leader)节点来解决第一个问题。也就是说将领导者节点作为唯一提议者&#xff0c;如图所示。这样就不存在多个提议者同时提交提案的情况&#xff0c;也就不存在提案冲突的情况了。这里补充一点:在论文中…

数字化技术可以促进中国企业创新吗?

数字化技术可以显著促进中国企业的创新。数字化技术&#xff0c;包括人工智能&#xff08;AI&#xff09;、区块链&#xff08;Blockchain&#xff09;、云计算&#xff08;Cloud computing&#xff09;、大数据&#xff08;big Data&#xff09;等&#xff0c;被称为ABCD技术&…

精准测试-Vue前端调用链影响变更分析之一

Vue前端调用链影响变更分析之一 一、背景二、工具调研1、 工具介绍&#xff1a;2、工具使用 三、工具落地集成方案&#xff08;待后续补充&#xff09;变更影响较为简单的实现变更影响较为复杂的实现1、全局关系数据库的构建2、变更影响的简单实现3、变更影响的复杂实现 一、背…

Detla lake with Java--入门

最近在研究数据湖&#xff0c;虽然不知道研究成果是否可以用于工作&#xff0c;但我相信机会总是留给有准备的人。 数据湖尤其是最近提出的湖仓一体化概念&#xff0c;很少有相关的资料&#xff0c;目前开源的项目就三个&#xff0c;分别是hudi, detla lake, iceberg。最终选择…

二维码门楼牌管理应用平台建设:档案管理的新篇章

文章目录 前言一、二维码门楼牌管理应用平台概述二、阵地档案管理的现状与挑战三、二维码门楼牌管理应用平台在阵地档案管理中的优势四、二维码门楼牌管理应用平台的建设与实施五、二维码门楼牌管理应用平台的未来发展六、结论 前言 随着信息技术的飞速发展&#xff0c;二维码…

如何下载AndroidStudio旧版本

文章目录 1. Android官方网站2. 往下滑找到历史版本归档3. 同意软件下载条款协议4. 下载旧版本Androidstudio1. Android官方网站 点击 Android官网AS下载页面 https://developer.android.google.cn/studio 进入AndroidStuido最新版下载页面,如下图: 2. 往下滑找到历史版本归…

无人机+集群组网+单兵图传:空地一体化组网技术详解

空地一体化组网技术是一种结合了无人机、集群自组网和单兵图传等多种技术的先进通信解决方案。这种技术方案的主要目的是在前线事故现场和后方指挥中心之间建立一个高效、稳定的通信链路&#xff0c;以确保信息的实时传输和指挥的顺畅进行。 首先&#xff0c;前端视频采集部分&…

视频美颜SDK与主播美颜工具的技术原理与应用场景分析

在直播视频领域中&#xff0c;视频美颜SDK和主播美颜工具发挥着至关重要的作用。本文将探讨这些工具的技术原理及其在不同应用场景中的应用。 一、视频美颜SDK的技术原理 1.1 图像处理技术 视频美颜SDK的核心技术之一是图像处理技术。根据用户设定的美颜参数进行相应的调整。…

【办公类-22-13】周计划系列(5-5)“周计划-05 周计划表格内教案部分“节日”清空改成“节日“” (2024年调整版本)Win32

背景需求&#xff1a; 本学期19周&#xff0c;用了近10周的时间&#xff0c;终于把周计划教案部分的内容补全了&#xff08;把所有教案、反思的文字都撑满一个单元格&#xff09;&#xff0c; 一、原始教案 二、新模板内的教案 三、手动添加文字后的样式&#xff08;修改教案…