目录

  • 搜索与图论
    • 1.树与图的存储
    • 2.树与图的遍历
    • 3.拓扑排序
    • 4.朴素dijkstra算法
    • 5.堆优化版dijkstra
    • 6.Bellman-Ford算法
    • 7.spfa 算法(队列优化的Bellman-Ford算法)
    • 8.spfa判断图中是否存在负环
    • 9.floyd算法
    • 10.朴素版prim算法
    • 11.Kruskal算法
    • 12.染色法判别二分图
    • 13.匈牙利算法

搜索与图论

1.树与图的存储

树是一种特殊的图,与图的存储方式相同。
对于无向图中的边a,b,存储两条有向边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);

2.树与图的遍历

时间复杂度 O(n+m), n 表示点数,m 表示边数
(1) 深度优先遍历

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) 宽度优先遍历

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);}}
}

3.拓扑排序

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

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;
}

4.朴素dijkstra算法

时间复杂是 O(n^2+m) n 表示点数,m 表示边数

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];
}

5.堆优化版dijkstra

时间复杂度 O(mlogn), n表示点数,m 表示边数
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];
}

6.Bellman-Ford算法

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

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];
}

7.spfa 算法(队列优化的Bellman-Ford算法)

时间复杂度 平均情况下 O(m),最坏情况下 O(nm), n表示点数,m 表示边数

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];
}

8.spfa判断图中是否存在负环

时间复杂度是 O(nm), n 表示点数,m表示边数

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;
}

9.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]);
}

10.朴素版prim算法

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

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;
}

11.Kruskal算法

时间复杂度是 O(mlogm), n 表示点数,m 表示边数

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;
}

12.染色法判别二分图

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

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;
}

13.匈牙利算法

时间复杂度是 O(nm), n 表示点数,m 表示边数

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 ++ ;
}

来自北京大学NOIP金牌选手yxc的常用代码模板3——搜索与图论相关推荐

  1. 来自北京大学NOIP金牌选手yxc的常用代码模板1——基础算法

    目录 1.快速排序算法模板 2.归并排序算法模板 3.整数二分算法模板 4.浮点数二分算法模板 5.高精度加法 6.高精度减法 7.高精度乘低精度 8.高精度除以低精度 9.一维前缀和 10.二维前缀 ...

  2. 来自北京大学NOIP金牌选手yxc的常用代码模板2——数据结构

    目录 1.单链表 2.双链表 3.栈 4.队列 5.单调栈 6. 单调队列 7.KMP 8.Trie树 9.并查集 10.堆 11.一般哈希 12.字符串哈希 13.C++ STL简介 1.单链表 / ...

  3. 来自北京大学NOIP金牌选手yxc的常用代码模板2,图灵学院和享学课堂

    // hh 表示队头,tt表示队尾的后一个位置 int q[N], hh = 0, tt = 0; // 向队尾插入一个数 q[tt ++ ] = x; if (tt == N) tt = 0; // ...

  4. 常用代码模板3——搜索与图论(Bellman-Ford算法 、spfa 算法、floyd算法、Kruskal算法、染色法、匈牙利算法 )

    目录 一.树与图的存储 二.树与图的遍历 (1) 深度优先遍历 -- 模板题 AcWing 846. 树的重心 (2) 宽度优先遍历 -- 模板题 AcWing 847. 图中点的层次 拓扑排序 -- ...

  5. 大二物竞金牌转北大计算机,2011年第28届全国中学生物理竞赛决赛金牌选手去向表...

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 2011年全国中学生物理竞赛决赛于10月29日至11月3日在西安交通大学举行.来自全国31个省市自治区的280名优秀选手参加决赛.经组织委员会评定,最终评 ...

  6. IOI APIO NOI NOIP 知名 选手 神犇 大牛 大神 博客

    IOI APIO NOI NOIP 知名 选手 神犇 大牛 大神 博客 福建    钟子谦 博客http://www.cnblogs.com/zzqsblog/ 现役选手,待更新. 广东    王之栋 ...

  7. 算法到底该怎么学?算法数据结构Java编程超全干货!(ACM金牌选手分享超牛学习路径~)...

    怎么才能最快的学习算法呢?(ps:文末附2022大厂面试真题~) 这是很多知友都关心的话题,作为一个ACM金牌选手,根据我的专业角度,特给大家来分享一下! 学习算法,切记不要一上来就开始啃<算法 ...

  8. 计算机毕业设——论文写作常用的资料搜索库

    收集专业学术资料是撰写毕业论文的重要组成部分,对毕业论文的优秀与否起重要作用.为大家介绍几种常用的资料搜索库,大家快快用起来吧. 图书查找 ►超星数字图书馆 超星数字图书馆目前拥有数字图书200多万册 ...

  9. 常用代码模板(Java)

    常用代码模板(JAVA) 基础算法 一 快速排序 void quickSort(int [] nums, int l, int r) {if (l >= r) {return;}int x = ...

最新文章

  1. 视觉+Transformer最新论文出炉,华为联合北大、悉尼大学发表
  2. 上传图片自动加水印html,帝国cms用户前台投稿上传图片自动加水印的实现方法...
  3. java类与对象明星,明星档案的
  4. RCP:给GEF编辑器添加网格和标尺。
  5. zabbix items复制
  6. 蓝桥杯2020年第十一届Python省赛第一题-门牌制作
  7. Microsoft Project项目管理实践
  8. 计算机网络正掩码怎么计算器,计算机网络课设子网掩码计算器.doc
  9. 蓝牙控制风扇的c语言程序,蓝牙风扇速度控制器的制作图解
  10. hⅰgh怎么读音发音英语_英语发音规则---gh
  11. PAT L3-001 凑零钱(01背包(布尔背包)+记录路径)
  12. Kafka消费者启动报错: Not authorized to access group
  13. 催眠曲用计算机怎么弹,在电脑中巧播“催眠曲”
  14. 语法-07-复合词,接尾词
  15. 阿里云服务器 API 的使用
  16. Unity如何画线条之美
  17. 专用神经网络处理器的芯片,cpu可以跑神经网络吗
  18. FaceX-Zoo | 使用PyTorch Toolbox进行人脸识别(附源代码)
  19. hive跑mr时报错,java.lang.IllegalArgumentException: The value of property yarn.resourcemanager.zk-address
  20. 最近进行的一次技术选型(工作流引擎)及相关知识介绍

热门文章

  1. win下 远程控制(教程+工具+黑客常用命令)
  2. RHCE怎么报名?需要什么条件?
  3. 单周期MIPS CPU设计
  4. 衡量电子计算机性能指标是,衡量计算机的性能指标有
  5. php-hyperf 使用Saber报 HTTP -4 Unknown: Linux Code 11: Resource temporarily unavailable
  6. 方叫兽教你如何正确的赚钱
  7. 24部经典电影的24句话
  8. css动画与渐变案例,使用动画和渐变做一个背景动态网页
  9. 【经济学视频课程】科斯定理的本质…
  10. PicPick软件免费版与正式版区别