[BZOJ1977][Beijing2010组队][LCA][Kruskal]次小生成树
2014-04-29 14:44
477 查看
[Problem Description]
小 C 最近学了很多最小生成树的算法,Prim 算法、Kurskal 算法、消圈算法等等。 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了。小 P 说,让小 C 求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是 EM,严格次小生成树选择的边集是 ES,那么需要满足:(value(e) 表示边 e的权值)
这下小
C 蒙了,他找到了你,希望你帮他解决这个问题。
[Algorithm]
LCA ST 最小生成树Kruskal
[Analysis]
首先求出最小生成树。可以想到严格次小生成树就是将一条边与最小生成树中的一条边进行替换,要求必须要替换代价且替换代价最小。枚举每条没有在最小生成树中的边,求出这条边连接的两个点在最小生成树中路径上的最大的边(这样替换代价最小)。由于这条边和两点间最小生成树上的路径构成了一个环,所以从环上任意去掉一个边,点都是联通的。至于求两点树上路径最大边,用lca的st算法。还要注意的是,由于是严格次小生成树,所以还要维护两点间树上路径上次大的边,当两点间树上路径最大边与枚举的边相等的时候,将次大的边与枚举的边替换。
[Pay Attention]
LCA算法注意别忘了将x和y更新!!我因为这个问题调了半天……以后要注意使用静态查错了……
小 C 最近学了很多最小生成树的算法,Prim 算法、Kurskal 算法、消圈算法等等。 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了。小 P 说,让小 C 求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是 EM,严格次小生成树选择的边集是 ES,那么需要满足:(value(e) 表示边 e的权值)
这下小
C 蒙了,他找到了你,希望你帮他解决这个问题。
[Algorithm]
LCA ST 最小生成树Kruskal
[Analysis]
首先求出最小生成树。可以想到严格次小生成树就是将一条边与最小生成树中的一条边进行替换,要求必须要替换代价且替换代价最小。枚举每条没有在最小生成树中的边,求出这条边连接的两个点在最小生成树中路径上的最大的边(这样替换代价最小)。由于这条边和两点间最小生成树上的路径构成了一个环,所以从环上任意去掉一个边,点都是联通的。至于求两点树上路径最大边,用lca的st算法。还要注意的是,由于是严格次小生成树,所以还要维护两点间树上路径上次大的边,当两点间树上路径最大边与枚举的边相等的时候,将次大的边与枚举的边替换。
[Pay Attention]
LCA算法注意别忘了将x和y更新!!我因为这个问题调了半天……以后要注意使用静态查错了……
[code]/************************************************************** Problem: 1977 User: gaotianyu1350 Language: C++ Result: Accepted Time:2920 ms Memory:35596 kb ****************************************************************/ #include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <queue> #include <algorithm> #include <iostream> using namespace std; const int MAXN = 100100; const int MAXM = 300100; const int MAXBIT = 22; const long long INF = 1e15; struct edge { int x, y, z; bool operator < (const edge b) const { return z < b.z; } } e[MAXM]; int point[MAXN] = {0}, next[MAXM] = {0}, v[MAXM], w[MAXM]; int tot = 0; bool check[MAXM] = {0}; int deep[MAXN] = {0}, f[MAXN][MAXBIT] = {0}, maxedge[MAXN][MAXBIT] = {0}, lessedge[MAXN][MAXBIT] = {0}; int n, m; long long ans = INF; long long minCost = 0; int theMaxBit; int father[MAXN]; inline void UnionInit() { for (int i = 1; i <= n; i++) father[i] = i; } inline void addedge(int x, int y, int z) { tot++; next[tot] = point[x]; point[x] = tot; v[tot] = y; w[tot] = z; } int getfather(int x) { if (father[x] == x) return x; else return father[x] = getfather(father[x]); } inline void update(int &theMax, int &theLess, int x1, int y1, int x2, int y2) { if (x1 > x2) { theMax = x1; theLess = max(y1, x2); } else if (x1 < x2) { theMax = x2; theLess = max(x1, y2); } else { theMax = x1; theLess = max(y1, y2); } } inline void MakeLca() { queue<int> q; q.push(1); deep[1] = 1; while (!q.empty()) { int now = q.front(); q.pop(); for (int temp = point[now]; temp; temp = next[temp]) if (v[temp] != f[now][0]) { q.push(v[temp]); f[v[temp]][0] = now; maxedge[v[temp]][0] = w[temp]; lessedge[v[temp]][0] = 0; deep[v[temp]] = deep[now] + 1; } } //theMaxBit = MAXBIT; theMaxBit = (int)(log(n) / log(2) + 1); for (int Bit = 1; Bit <= theMaxBit; Bit++) for (int i = 1; i <= n; i++) { f[i][Bit] = f[f[i][Bit - 1]][Bit - 1]; update(maxedge[i][Bit], lessedge[i][Bit], maxedge[i][Bit - 1], lessedge[i][Bit - 1], maxedge[f[i][Bit - 1]][Bit - 1], lessedge[f[i][Bit - 1]][Bit - 1]); } } inline void Up(int &x, int tar, int &theMax, int &theLess) { for (int i = theMaxBit; i >= 0; i--) if (deep[f[x][i]] >= tar) { update(theMax, theLess, theMax, theLess, maxedge[x][i], lessedge[x][i]); x = f[x][i]; } } void Query(int x, int y, int &theMax, int &theLess) { theMax = -1; theLess = -1; if (deep[x] < deep[y]) { int temp = x; x = y; y = temp; } Up(x, deep[y], theMax, theLess); if (x == y) return; for (int i = theMaxBit; i >= 0; i--) if (f[x][i] != f[y][i]) { update(theMax, theLess, theMax, theLess, maxedge[x][i], lessedge[x][i]); update(theMax, theLess, theMax, theLess, maxedge[y][i], lessedge[y][i]); x = f[x][i]; y = f[y][i]; } update(theMax, theLess, theMax, theLess, maxedge[x][0], lessedge[x][0]); update(theMax, theLess, theMax, theLess, maxedge[y][0], lessedge[y][0]); } int main() { //freopen("input.txt", "r", stdin); scanf("%d%d", &n, &m); UnionInit(); for (int i = 1; i <= m; i++) scanf("%d%d%d", &e[i].x, &e[i].y, &e[i].z); sort(e + 1, e + 1 + m); for (int i = 1; i <= m; i++) { int fx = getfather(e[i].x); int fy = getfather(e[i].y); if (fx != fy) { check[i] = true; father[fx] = fy; addedge(e[i].x, e[i].y, e[i].z); addedge(e[i].y, e[i].x, e[i].z); minCost += e[i].z; } } MakeLca(); for (int i = 1; i <= m; i++) if (!check[i]) { int theMax, theLess; Query(e[i].x, e[i].y, theMax, theLess); if (theMax != e[i].z) { long long temp = minCost - theMax; temp += e[i].z; ans = temp < ans ? temp : ans; } else if (theLess > 0) { long long temp = minCost - theLess; temp += e[i].z; ans = temp < ans ? temp : ans; } } printf("%lld\n", ans); }
相关文章推荐
- [bzoj1003] [ZJOI2006]物流运输trans
- [bzoj1500][NOI2005]维修数列
- [bzoj1208] [HNOI2004]宠物收养所
- [bzoj1269][AHOI2006]文本编辑器editort
- [bzoj1503][NOI2004]郁闷的出纳员
- [BZOJ2324][ZJOI2011][最小费用最大流]营救皮卡丘
- [BZOJ1500][NOI2005][Splay]维修数列
- [BZOJ1997][HNOI2010][2-sat]Planar
- [BZOJ3038][线段树]上帝造题的七分钟2
- [BZOJ1834][ZJOI2010][最大流][最小费用最大流]网络扩容
- [BZOJ1507][NOI2003][Rope]Editor
- [BZOJ1492][NOI2007][斜率优化][动态凸包][DP][分治]货币兑换cash
- [BZOJ1303][CQOI2009]中位数图
- [BZOJ1211][HNOI2004][prufer序列][排列]树的计数
- [BZOJ1257][CQOI2007]余数之和
- [BZOJ1191][HNOI2006][二分图匹配][匈牙利算法]超级英雄hero
- [BZOJ3196][TYVJ3196][树套数][区间第k大]二逼平衡树
- [BZOJ3171][TJOI2013][最小费用最大流]循环格
- [BZOJ1024][SCOI2009][DFS]生日快乐
- [BZOJ1226][SDOI2009][状态压缩DP]学校食堂Dining