常用代码模板3——搜索与图论

news/2024/11/18 17:20:11/文章来源:https://www.cnblogs.com/kkman2000/p/18553167

算法基础课相关代码模板 

树与图的存储

树是一种特殊的图,与图的存储方式相同。
对于无向图中的边ab,存储两条有向边a->b, b->a。
因此我们可以只考虑有向图的存储。

(1) 邻接矩阵:g[a][b] 存储边a->b

(2) 邻接表:

// 对于每个点k,开一个单链表,存储k所有可以走到的点。h[k]存储这个单链表的头结点
int h[N], e[N], ne[N], idx;// 添加一条边a->b
void add(int a, int b)
{e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}// 初始化
idx = 0;
memset(h, -1, sizeof h);

树与图的遍历

时间复杂度 O(n+m)O(n+m), nn 表示点数,mm 表示边数

(1) 深度优先遍历 —— 模板题 luogu 846. 树的重心

int dfs(int u)
{st[u] = true; // st[u] 表示点u已经被遍历过for (int i = h[u]; i != -1; i = ne[i]){int j = e[i];if (!st[j]) dfs(j);}
}

(2) 宽度优先遍历 —— 模板题 luogu 847. 图中点的层次

queue<int> q;
st[1] = true; // 表示1号点已经被遍历过
q.push(1);while (q.size())
{int t = q.front();q.pop();for (int i = h[t]; i != -1; i = ne[i]){int j = e[i];if (!st[j]){st[j] = true; // 表示点j已经被遍历过q.push(j);}}
}

拓扑排序 —— 模板题 luogu 848. 有向图的拓扑序列

时间复杂度 O(n+m)O(n+m), nn 表示点数,mm 表示边数
bool topsort()
{int hh = 0, tt = -1;// d[i] 存储点i的入度for (int i = 1; i <= n; i ++ )if (!d[i])q[ ++ tt] = i;while (hh <= tt){int t = q[hh ++ ];for (int i = h[t]; i != -1; i = ne[i]){int j = e[i];if (-- d[j] == 0)q[ ++ tt] = j;}}// 如果所有点都入队了,说明存在拓扑序列;否则不存在拓扑序列。return tt == n - 1;
}

朴素dijkstra算法 —— 模板题 luogu 849. Dijkstra求最短路 I

时间复杂是 O(n2+m)O(n2+m), nn 表示点数,mm 表示边数
int g[N][N];  // 存储每条边
int dist[N];  // 存储1号点到每个点的最短距离
bool st[N];   // 存储每个点的最短路是否已经确定// 求1号点到n号点的最短路,如果不存在则返回-1
int dijkstra()
{memset(dist, 0x3f, sizeof dist);dist[1] = 0;for (int i = 0; i < n - 1; i ++ ){int t = -1;     // 在还未确定最短路的点中,寻找距离最小的点for (int j = 1; j <= n; j ++ )if (!st[j] && (t == -1 || dist[t] > dist[j]))t = j;// 用t更新其他点的距离for (int j = 1; j <= n; j ++ )dist[j] = min(dist[j], dist[t] + g[t][j]);st[t] = true;}if (dist[n] == 0x3f3f3f3f) return -1;return dist[n];
}

堆优化版dijkstra —— 模板题 luogu 850. Dijkstra求最短路 II

时间复杂度 O(mlogn)O(mlogn), nn 表示点数,mm 表示边数
typedef pair<int, int> PII;int n;      // 点的数量
int h[N], w[N], e[N], ne[N], idx;       // 邻接表存储所有边
int dist[N];        // 存储所有点到1号点的距离
bool st[N];     // 存储每个点的最短距离是否已确定// 求1号点到n号点的最短距离,如果不存在,则返回-1
int dijkstra()
{memset(dist, 0x3f, sizeof dist);dist[1] = 0;priority_queue<PII, vector<PII>, greater<PII>> heap;heap.push({0, 1});      // first存储距离,second存储节点编号while (heap.size()){auto t = heap.top();heap.pop();int ver = t.second, distance = t.first;if (st[ver]) continue;st[ver] = true;for (int i = h[ver]; i != -1; i = ne[i]){int j = e[i];if (dist[j] > distance + w[i]){dist[j] = distance + w[i];heap.push({dist[j], j});}}}if (dist[n] == 0x3f3f3f3f) return -1;return dist[n];
}

Bellman-Ford算法 —— 模板题 luogu 853. 有边数限制的最短路

时间复杂度 O(nm)O(nm), nn 表示点数,mm 表示边数

注意在模板题中需要对下面的模板稍作修改,加上备份数组,详情见模板题。

int n, m;       // n表示点数,m表示边数
int dist[N];        // dist[x]存储1到x的最短路距离struct Edge     // 边,a表示出点,b表示入点,w表示边的权重
{int a, b, w;
}edges[M];// 求1到n的最短路距离,如果无法从1走到n,则返回-1。
int bellman_ford()
{memset(dist, 0x3f, sizeof dist);dist[1] = 0;// 如果第n次迭代仍然会松弛三角不等式,就说明存在一条长度是n+1的最短路径,由抽屉原理,路径中至少存在两个相同的点,说明图中存在负权回路。for (int i = 0; i < n; i ++ ){for (int j = 0; j < m; j ++ ){int a = edges[j].a, b = edges[j].b, w = edges[j].w;if (dist[b] > dist[a] + w)dist[b] = dist[a] + w;}}if (dist[n] > 0x3f3f3f3f / 2) return -1;return dist[n];
}

spfa 算法(队列优化的Bellman-Ford算法) —— 模板题 luogu 851. spfa求最短路

时间复杂度 平均情况下 O(m)O(m),最坏情况下 O(nm)O(nm), nn 表示点数,mm 表示边数
int n;      // 总点数
int h[N], w[N], e[N], ne[N], idx;       // 邻接表存储所有边
int dist[N];        // 存储每个点到1号点的最短距离
bool st[N];     // 存储每个点是否在队列中// 求1号点到n号点的最短路距离,如果从1号点无法走到n号点则返回-1
int spfa()
{memset(dist, 0x3f, sizeof dist);dist[1] = 0;queue<int> q;q.push(1);st[1] = true;while (q.size()){auto t = q.front();q.pop();st[t] = false;for (int i = h[t]; i != -1; i = ne[i]){int j = e[i];if (dist[j] > dist[t] + w[i]){dist[j] = dist[t] + w[i];if (!st[j])     // 如果队列中已存在j,则不需要将j重复插入{q.push(j);st[j] = true;}}}}if (dist[n] == 0x3f3f3f3f) return -1;return dist[n];
}

spfa判断图中是否存在负环 —— 模板题 luogu 852. spfa判断负环

时间复杂度是 O(nm)O(nm), nn 表示点数,mm 表示边数
int n;      // 总点数
int h[N], w[N], e[N], ne[N], idx;       // 邻接表存储所有边
int dist[N], cnt[N];        // dist[x]存储1号点到x的最短距离,cnt[x]存储1到x的最短路中经过的点数
bool st[N];     // 存储每个点是否在队列中// 如果存在负环,则返回true,否则返回false。
bool spfa()
{// 不需要初始化dist数组// 原理:如果某条最短路径上有n个点(除了自己),那么加上自己之后一共有n+1个点,由抽屉原理一定有两个点相同,所以存在环。queue<int> q;for (int i = 1; i <= n; i ++ ){q.push(i);st[i] = true;}while (q.size()){auto t = q.front();q.pop();st[t] = false;for (int i = h[t]; i != -1; i = ne[i]){int j = e[i];if (dist[j] > dist[t] + w[i]){dist[j] = dist[t] + w[i];cnt[j] = cnt[t] + 1;if (cnt[j] >= n) return true;       // 如果从1号点到x的最短路中包含至少n个点(不包括自己),则说明存在环if (!st[j]){q.push(j);st[j] = true;}}}}return false;
}

floyd算法 —— 模板题 luogu 854. Floyd求最短路

时间复杂度是 O(n3)O(n3), nn 表示点数
初始化: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]);
}

朴素版prim算法 —— 模板题 luogu 858. Prim算法求最小生成树

时间复杂度是 O(n2+m)O(n2+m), nn 表示点数,mm 表示边数
int n;      // n表示点数
int g[N][N];        // 邻接矩阵,存储所有边
int dist[N];        // 存储其他点到当前最小生成树的距离
bool st[N];     // 存储每个点是否已经在生成树中// 如果图不连通,则返回INF(值是0x3f3f3f3f), 否则返回最小生成树的树边权重之和
int prim()
{memset(dist, 0x3f, sizeof dist);int res = 0;for (int i = 0; i < n; i ++ ){int t = -1;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;if (i) res += dist[t];st[t] = true;for (int j = 1; j <= n; j ++ ) dist[j] = min(dist[j], g[t][j]);}return res;
}

Kruskal算法 —— 模板题 luogu 859. Kruskal算法求最小生成树

时间复杂度是 O(mlogm)O(mlogm), nn 表示点数,mm 表示边数
int n, m;       // n是点数,m是边数
int p[N];       // 并查集的父节点数组struct Edge     // 存储边
{int a, b, w;bool operator< (const Edge &W)const{return w < W.w;}
}edges[M];int find(int x)     // 并查集核心操作
{if (p[x] != x) p[x] = find(p[x]);return p[x];
}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 ++ ){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;return res;
}

染色法判别二分图 —— 模板题 luogu 860. 染色法判定二分图

时间复杂度是 O(n+m)O(n+m), nn 表示点数,mm 表示边数
int n;      // n表示点数
int h[N], e[M], ne[M], idx;     // 邻接表存储图
int color[N];       // 表示每个点的颜色,-1表示未染色,0表示白色,1表示黑色// 参数:u表示当前节点,c表示当前点的颜色
bool dfs(int u, int c)
{color[u] = c;for (int i = h[u]; i != -1; i = ne[i]){int j = e[i];if (color[j] == -1){if (!dfs(j, !c)) return false;}else if (color[j] == c) return false;}return true;
}bool check()
{memset(color, -1, sizeof color);bool flag = true;for (int i = 1; i <= n; i ++ )if (color[i] == -1)if (!dfs(i, 0)){flag = false;break;}return flag;
}

匈牙利算法 —— 模板题 luogu 861. 二分图的最大匹配

时间复杂度是 O(nm)O(nm), nn 表示点数,mm 表示边数
int n1, n2;     // n1表示第一个集合中的点数,n2表示第二个集合中的点数
int h[N], e[M], ne[M], idx;     // 邻接表存储所有边,匈牙利算法中只会用到从第一个集合指向第二个集合的边,所以这里只用存一个方向的边
int match[N];       // 存储第二个集合中的每个点当前匹配的第一个集合中的点是哪个
bool st[N];     // 表示第二个集合中的每个点是否已经被遍历过bool find(int x)
{for (int i = h[x]; i != -1; i = ne[i]){int j = e[i];if (!st[j]){st[j] = true;if (match[j] == 0 || find(match[j])){match[j] = x;return true;}}}return false;
}// 求最大匹配数,依次枚举第一个集合中的每个点能否匹配第二个集合中的点
int res = 0;
for (int i = 1; i <= n1; i ++ )
{memset(st, false, sizeof st);if (find(i)) res ++ ;
}

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

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

相关文章

DML

1.通过使用insert into 表名 values(值1,值2,值3)如果插入的数据与列一一对应,那么可以省略列名,但如果希望向指定列上插入数据,就需要写出列名 2.insert into 表名(列名1,列名2)values(值1,值2);也可以一次性向数据库中插入多条数据 3.insert into 表名(列名1,列名…

多部门协作效率低下?项目管理工具能帮你解决!

在现代企业中,不同部门间的协作日益成为工作成功的关键。无论是市场部、产品部,还是运营部、财务部,部门之间的高效协作能显著提升整体产出,避免信息孤岛与资源浪费。然而,在实际工作中,跨部门合作常常面临各种挑战,比如沟通不畅、信息分散、目标不一致等。而项目管理软…

修改IDEA中Servlet创建的模板

一、原Servlet模板创建出来的格式样式二、按图步骤修改注释参数 1.点击File->选择Settings,按下图步骤进入设置项。修改前的模板样式2.修改类创建时的默认方法三、重新创建Servlet时,新模板样式

202222313 2024-2025-1 《网络与系统攻防技术》实验六实验报告

1. 实验内容 1.1 实验要求 (1)掌握metasploit、nmap的用法。 (2)学习前期渗透的方法。 (3)利用4个漏洞,实现对靶机的攻击。 1.2 学习内容 (1)metasploit的用法:可以简单总结为“Search-Use-Show-Set-Exploit/run”。 (2)四种漏洞的原理。Vsftpd源码包后门漏洞:在特定版本的v…

创建表(1)

1.切换操作的数据库,默认是在MySQL中进行操作2.创建表,遵循固定格式,枚举可用enum(‘’,‘’)限制条件可用notnull 默认可设置default‘ ’3.修改表:可以用alter table进行修改 alter table 表名 add 列名 数据类型 列级约束条件; alter table 表名 drop column 列名 …

Flutter项目实战(1):通用项目框架搭建

下面介绍 Flutter 最基本的通用项目框架搭建,同时实现了一个登录界面图标和登录界面。 先看下效果图:使用ScreenUtilInit自适应界面大小; 使用Stack支持多个子界面在同一个全屏主界面上选择显示; 使用 Get 插件实现界面之间的跳转和国际化翻译; 界面都通过Transform实现了…

Rocky安装htop

本篇抄的,放在这里防止自己忘记 两条命令: dnf install epel-release -y dnf install htop -yhtop测试: [root@localhost ~]# htop //回车后出现如下图,按q退出

数据采集与融合第四次作业

码云仓库地址 https://gitee.com/sun-jiahui22/crawl_project作业1仓库地址 https://gitee.com/sun-jiahui22/crawl_project/tree/master/作业4/实验4.1作业2的仓库地址 https://gitee.com/sun-jiahui22/crawl_project/tree/master/作业4/实验4.2作业3的仓库地址 https://gitee…

2-SQL注入渗透与攻防

1、SQL注入基础 1.1 什么是sql注入 一、SQL注入概述 二、数据库概述 1.关系型数据库 关系型数据库,存储格式可以直观的反映实体间的关系,和常见的表格比较相似 关系型数据库中表与表之间有很多复杂的关联关系的 常见的关系型数据库有MySQL、Orcale、PostgreSQL、SQL Server等…

vscode go语言注释语句黄色波浪线

go语言注释代码总是飘着黄色波浪线提示:(with optional leading article) (ST1021)go-staticcheck,非常影响观感。 经过查询发现,go-staticcheck 是一个用于 Go 代码静态分析的工具,用来检测代码中的潜在问题、代码规范以及常见的错误。本次错误信息来自 go-staticcheck 中…