图算法小结
来源:互联网 发布:关于初中语文的软件 编辑:程序博客网 时间:2024/06/08 09:09
本目总结常见的图算法。
kruskal
构造mst,按边从小到大遍历,如果边的响铃节点位于不同的集合,那么该边是mst当中的一条边。这个地方需要并查集的知识。
- 题目:[jobdu-1017]
- 代码
#include <iostream>#include <vector>#include <algorithm>#define N 100int tree[N + 8];struct Edge { int u; int v; int w; Edge() {} Edge( int uu, int vv, int ww ) : u(uu), v(vv), w(ww) {} bool operator<( const Edge& rhs ) const { return w< rhs.w; }};typedef std::vector<Edge> EdgeList;int find_root(int x){ if( tree[x] == -1 ) return x; else{ int tmp = find_root( tree[x] ); tree[x] = tmp; return tmp; }}int main( void ){ int n = 0; while( std::cin >> n, n ){ EdgeList edge_list; for( int i = 1; i <= n; ++i ) tree[i] = -1; for( int i = 0; i < n*(n-1)/2; ++i ){ int u, v, w; std::cin >> u >> v >> w; Edge edge(u, v, w); edge_list.push_back(edge); } std::sort( edge_list.begin(), edge_list.end() ); int ans = 0; int n = edge_list.size(); for(int i = 0; i < n; ++i){ int uu = edge_list[i].u; int vv = edge_list[i].v; int ww = edge_list[i].w; int a = find_root(uu); int b = find_root(vv); if( a == b ) continue; else{ ans += ww; tree[a] = b; } } std::cout << ans << std::endl; } return 0;}
dijkstra
基于路径长度依次递增,所以w > 0
- 题目:[jobdu-1447]
- 代码
#include <iostream>#include <vector>#include <limits.h>#define N 100struct Edge { int node; int weight; Edge() {} Edge( int n, int w ) : node(n), weight(w) {}};typedef std::vector<Edge> EdgeList;EdgeList adj_list[N + 8];int d[N+8];int flag[N+8];int dijk( int n, int s, int t );void relax( int u, int v, int w );int main( void ){ int n,m; while(std::cin >> n >> m){ if( !n && !m ) break; for( int i = 1; i <= n; ++i ) adj_list[i].clear(); for( int i = 0; i < m; ++i ){ int u,v,w; std::cin >> u >> v >> w; Edge edge(v,w); adj_list[u].push_back(edge); Edge edge1(u,w); adj_list[v].push_back(edge1); } int ans = dijk( n, 1, n ); std::cout << ans << std::endl; } return 0;}int dijk( int n, int s, int t ){ for( int i = 1; i <= n; ++i ){ d[i] = INT_MAX; } d[s] = 0; for( int i = 1; i <= n; ++i ) flag[i] = 0; int cnt = n; while(cnt--){ int u; int min = INT_MAX; for( int i = 1; i <= n; ++i ){ if( flag[i] ) continue; if( d[i] < min ){ u = i; min = d[i]; } } flag[u] = 1; if( u == t ) break; int sz = adj_list[u].size(); for( int k = 0; k < sz; ++k ){ int v = adj_list[u][k].node; int w = adj_list[u][k].weight; relax(u, v, w); } } return d[t];}void relax( int u, int v, int w ){ if( d[u] + w < d[v] ) d[v] = d[u] + w;}
bellman-ford
需要注意的是,bellman-ford的基本思路是按照层次依次松弛的做法。而dijk则是按照路径长度依次递增。整体思路不同。
bellman-ford之所以要松弛V-1次,原因在于,图最长的一条路径是他退化成链表的情形。此时N个顶点的图,最长的边为N-1。每次,松弛所有边。
如果,松弛完所有层次之后。
再松弛依次发现还可以松弛,那么证明,这个图当中存在负边。
- 题目:同上
- 代码
#include <iostream>#include <vector>#include <limits.h>#define N 100struct Edge { int node; int weight; Edge() {} Edge( int n, int w ) : node(n), weight(w) {}};typedef std::vector<Edge> EdgeList;EdgeList adj_list[N + 8];int d[N+8];int bellman_ford( int n, int s, int t );void relax( int u, int v, int w );int main( void ){ int n,m; while(std::cin >> n >> m){ if( !n && !m ) break; for( int i = 1; i <= n; ++i ) adj_list[i].clear(); for( int i = 0; i < m; ++i ){ int u,v,w; std::cin >> u >> v >> w; Edge edge(v,w); adj_list[u].push_back(edge); Edge edge1(u,w); adj_list[v].push_back(edge1); } int ans = bellman_ford( n, 1, n ); std::cout << ans << std::endl; } return 0;}int bellman_ford( int n, int s, int t ){ for(int i = 1; i <= n; ++i) d[i] = INT_MAX; d[s] = 0; for( int cnt = 0; cnt < n-1; ++cnt ){ // V-1 // relax every edge for( int u = 1; u <= n; ++u ){ int sz = adj_list[u].size(); for( int k = 0; k < sz; ++k ){ int v = adj_list[u][k].node; int w = adj_list[u][k].weight; relax(u, v, w); } } } for( int u = 1; u <= n; ++u ){ int sz = adj_list[u].size(); for( int k = 0; k < sz; ++k ){ int v = adj_list[u][k].node; int w = adj_list[u][k].weight; if( d[u] + w < d[v] ) return -1; } } return d[t];}void relax( int u, int v, int w ){ if( d[u] + w < d[v] ) d[v] = d[u] + w;}
spfa
大体的思想来自于bellman-ford,但是,每次只是松弛有效的边,不用松弛所有的边。这是他的主要思想。
增加了两个数据结构:
visited[v],表示v这个节点是否在队列中
count[v],表示v的入队次数,如果超过N-1次。存在负边,比如只有两个顶点的图,存在两条边,有一条是负的。存在这种情形。
#include <iostream>#include <vector>#include <limits.h>#include <queue>#define N 100struct Edge { int node; int weight; Edge() {} Edge( int n, int w ) : node(n), weight(w) {}};typedef std::vector<Edge> EdgeList;EdgeList adj_list[N + 8];int d[N+8];int visited[N+8]; // in the queue or notint count[N+8];int spfa( int n, int s, int t );int main( void ){ int n,m; while(std::cin >> n >> m){ if( !n && !m ) break; for( int i = 1; i <= n; ++i ) adj_list[i].clear(); for( int i = 0; i < m; ++i ){ int u,v,w; std::cin >> u >> v >> w; Edge edge(v,w); adj_list[u].push_back(edge); Edge edge1(u,w); adj_list[v].push_back(edge1); } int ans = spfa( n, 1, n ); std::cout << ans << std::endl; } return 0;}int spfa( int n, int s, int t ){ for(int i = 1; i <= n; ++i) d[i] = INT_MAX; d[s] = 0; for( int i = 1; i <= n; ++i ){ visited[i] = 0; count[i] = 0; } std::queue<int> que; que.push(s); visited[s] = 1; count[s] += 1; while( !que.empty() ){ int u = que.front(); que.pop(); visited[u] = 0; int sz = adj_list[u].size(); for( int k = 0; k < sz; ++k ){ int v = adj_list[u][k].node; int w = adj_list[u][k].weight; if( d[u] + w < d[v] ){ d[v] = d[u] + w; if( visited[v] == 0 ){ que.push(v); visited[v] = 1; count[v] += 1; if( count[v] > n-1 ) return -1; } } } } return d[t];}
topsort
拓扑排序是这样一种顶点序列,如果vi到vj存在一条边,那么vi排在vj的前面。具体的做法是每次寻找度为0的点,然后删除这些点所指向的边。重复n次或者指导没有度为0的点可以删除。
拓扑排序之所以可能存在多种的情形在于,度为0的点选择不同。
- 题目: [jobdu-1448]
- 代码
#include <iostream>#include <vector>#include <queue>#define N 100typedef std::vector<int> EdgeList;EdgeList adj_list[N + 8];int indegree[N + 8];int main( void ){ int n, m; while( std::cin >> n >> m ){ if( !n && !m ) break; for( int i = 0; i < n; ++i ){ adj_list[i].clear(); indegree[i] = 0; } for( int i = 0; i < m; ++i ){ int u,v; std::cin >> u >> v; adj_list[u].push_back(v); ++indegree[v]; } std::queue<int> q; for( int i = 0; i < n; ++i ){ if( !indegree[i] ) q.push(i); } int cnt = 0; while(!q.empty()){ int u = q.front(); q.pop(); ++cnt; int sz = adj_list[u].size(); for( int k = 0; k < sz; ++k ){ int v = adj_list[u][k]; --indegree[v]; if( !indegree[v] ) q.push(v); } } if( cnt == n ) std::cout << "YES" << std::endl; else std::cout << "NO" << std::endl; } return 0;}
阅读全文
0 0
- 图论算法小结
- 图算法小结
- 图论算法小结
- 图算法小结
- 算法小结
- 算法小结
- 算法小结
- 算法小结
- 图及其遍历的各种算法小结
- 图论专题小结:最短路算法
- 图算法小结(并查集)
- 图论算法小结:欧拉回路
- 二分图的匹配算法小结
- 图论算法小结:网络流及其算法
- 图论专题小结:最大流算法之Dinic算法
- 图论专题小结:最大流算法之ISAP算法
- 排序算法小结
- 排序算法小结
- linux cpu load学习笔记
- Java动态代理之JDK动态代理
- 2017 ACM/ICPC Asia Regional Shenyang Online:transaction transaction transaction
- JDBC数据库访问技术
- 总有人记得
- 图算法小结
- Leetcode 56.Merge Intervals
- 正则表达式学习记录(持续更新)
- 《Netty学习》(七)EventLoop学习
- Windows10下安装GPU版本的Tensorflow
- 反汇编分析之:虚函数,虚表,多态
- Linux(CentOS 7_x64位)系统下安装DOCK6.8
- 沈阳网络赛小结
- 利用ffmpeg批量转码视频