邦德,白书P345UVa11345(最小生成树,无根树转有根树,最近公共祖先,二进制快速查找)
来源:互联网 发布:java中文件流 编辑:程序博客网 时间:2024/05/17 05:55
本题是一道非常非常优秀的题目,题目的综合性,考察的知识点实在是太丰富了。而且刘的算法思路也足够精简优化,是一道知道反复复习多次的题目。
知识积累:
1.首先,求求最小瓶颈路问题可不是最短路问题,因为最长边最小的路径不一定是最短路。比如A到B之间有两条路径,其中一条所经过的边的权值为1,1,1,1,1,1,1,1,第二条所经过的路径为2。
2.由于Kruskal算法生成的最小生成树仅仅是原图的一个子图,是无根树,所需要无根树转有根树。
无根树转有根数算法:
dfs(0, -1, 0);//dfs无根树转有根数 void dfs(int u, int fa, int level) { solver.L[u] = level; for(int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if(v != fa) { solver.fa[v] = u; solver.cost[v] = C[u][i]; dfs(v, u, level+1); } }}
其中根节点的fa[]数组并未赋初始值,需要全局赋值。
3.二进制快速查找:
初始化:
void preprocess() { for(int i = 0; i < n; i++) { anc[i][0] = fa[i]; maxcost[i][0] = cost[i]; for(int j = 1; (1 << j) < n; j++) anc[i][j] = -1; } for(int j = 1; (1 << j) < n; j++) for(int i = 0; i < n; i++) if(anc[i][j-1] != -1) { int a = anc[i][j-1]; anc[i][j] = anc[a][j-1]; maxcost[i][j] = max(maxcost[i][j-1], maxcost[a][j-1]); } }
将每个元素与它前面第2^i个元素相连接。2^i
if(L[p] < L[q]) swap(p, q); for(log = 1; (1 << log) <= L[p]; log++); log--; int ans = -INF; for(int i = log; i >= 0; i--) if (L[p] - (1 << i) >= L[q]) { ans = max(ans, maxcost[p][i]); p = anc[p][i];}
核心思想,2^0,2^1,2^2……2^n之间随意组合可以组成2^n到2^n+1次方之间任意的一个数字。由此实现给定一个元素n,可通过logN的时间迅速找到其前面任意位置的元素。
// UVa11354 Bond// Rujia Liu#include<cstdio>#include<algorithm>using namespace std;const int maxn = 100000 + 10;const int logmaxn = 20;const int INF = 1000000000;struct LCA { int n; int fa[maxn]; // 父亲数组 int cost[maxn]; // 和父亲的费用 int L[maxn]; // 层次(根节点层次为0) int anc[maxn][logmaxn]; // anc[p][i]是结点p的第2^i级父亲。anc[i][0] = fa[i] int maxcost[maxn][logmaxn]; // maxcost[p][i]是i和anc[p][i]的路径上的最大费用 // 预处理,根据fa和cost数组求出anc和maxcost数组 void preprocess() { for(int i = 0; i < n; i++) { anc[i][0] = fa[i]; maxcost[i][0] = cost[i]; for(int j = 1; (1 << j) < n; j++) anc[i][j] = -1; } for(int j = 1; (1 << j) < n; j++) for(int i = 0; i < n; i++) if(anc[i][j-1] != -1) { int a = anc[i][j-1]; anc[i][j] = anc[a][j-1]; maxcost[i][j] = max(maxcost[i][j-1], maxcost[a][j-1]); } } // 求p到q的路径上的最大权 int query(int p, int q) { int tmp, log, i; if(L[p] < L[q]) swap(p, q); for(log = 1; (1 << log) <= L[p]; log++); log--; int ans = -INF; for(int i = log; i >= 0; i--) if (L[p] - (1 << i) >= L[q]) { ans = max(ans, maxcost[p][i]); p = anc[p][i];} if (p == q) return ans; // LCA为p for(int i = log; i >= 0; i--) if(anc[p][i] != -1 && anc[p][i] != anc[q][i]) { ans = max(ans, maxcost[p][i]); p = anc[p][i]; ans = max(ans, maxcost[q][i]); q = anc[q][i]; } ans = max(ans, cost[p]); ans = max(ans, cost[q]); return ans; // LCA为fa[p](它也等于fa[q]) } };LCA solver;#include<cstdio>#include<vector>int pa[maxn];int findset(int x) { return pa[x] != x ? pa[x] = findset(pa[x]) : x; } vector<int> G[maxn], C[maxn];void dfs(int u, int fa, int level) { solver.L[u] = level; for(int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if(v != fa) { solver.fa[v] = u; solver.cost[v] = C[u][i]; dfs(v, u, level+1); } }}struct Edge { int x, y, d; bool operator < (const Edge& rhs) const { return d < rhs.d; }};const int maxm = 100000;Edge e[maxm];int main() { int kase = 0, n, m, x, y, d, Q; while(scanf("%d%d", &n, &m) == 2 && n) { for(int i = 0; i < m; i++) { scanf("%d%d%d", &x, &y, &d); e[i] = (Edge){ x-1, y-1, d };//语法细节再次注意 } // 最小生成树 sort(e, e+m); for(int i = 0; i < n; i++) { pa[i] = i; G[i].clear(); C[i].clear(); } for(int i = 0; i < m; i++) { int x = e[i].x, y = e[i].y, d = e[i].d, u = findset(x), v = findset(y); if(u != v) { pa[u] = v; G[x].push_back(y); C[x].push_back(d); G[y].push_back(x); C[y].push_back(d); } } // 化成有根树 solver.n = n; dfs(0, -1, 0);//dfs无根树转有根数 solver.preprocess(); if(++kase != 1) printf("\n"); scanf("%d", &Q); while(Q--) { scanf("%d%d", &x, &y); printf("%d\n", solver.query(x-1, y-1)); } } return 0;}
阅读全文
0 0
- 邦德,白书P345UVa11345(最小生成树,无根树转有根树,最近公共祖先,二进制快速查找)
- 查找最近公共祖先结点
- UVA - 11354Bond最小生成树,LCA寻找最近公共祖先
- LeetCode -- 查找最小公共祖先
- 二叉查找树(6) - 最近公共祖先LCA
- 查找两个节点最近的公共祖先
- 树的最近公共祖先
- 二叉树最近公共祖先
- 二叉树最近公共祖先
- 二叉树-最近公共祖先
- 二叉树查找公共祖先
- 【NOIp复习】最近公共祖先LCA&区间最大最小RMQ
- 二叉树中的最近公共祖先问题
- 二叉树-最近公共祖先(LCA)
- 二叉树最近公共祖先(LCA)
- 二叉树最近公共祖先节点
- 二叉树的最近公共祖先
- 算法基础 - 树的最近公共祖先
- CSS注释语法
- 爬虫下载壁纸,并设置壁纸自动切换
- 第44条 为所有导出的API元素编写文档注释
- 小程序合集
- [LC] 224. Basic Calculator
- 邦德,白书P345UVa11345(最小生成树,无根树转有根树,最近公共祖先,二进制快速查找)
- JETSON TX2源码编译安装tensorflow1.4.0
- char*,const char*和string的相互转换
- Intellij IDEA生成JavaDoc
- java的JTable组件显示mysql数据库表中的数据以及将JTable表格中的数据存储到数据库中
- combo
- Creating Maintainable APIs.pdf 英文原版 免费下载
- Myeclipse文档注释如何提炼(导出)成自己的API帮助文档?
- MySQL 必知必会