Skip to content

Commit 4f50bc8

Browse files
committed
add 曼哈顿最小生成树
1 parent 69f1bb3 commit 4f50bc8

File tree

2 files changed

+99
-0
lines changed

2 files changed

+99
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@
188188
- Prim
189189
- 单度限制最小生成树
190190
- 次小生成树
191+
- 曼哈顿距离最小生成树
191192
- 最小差值生成树
192193
- 最小树形图
193194
- 朱刘算法

copypasta/graph.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,6 +1115,7 @@ func (*graph) shortestPathDijkstra(in io.Reader, n, m, st int) (dist []int64) {
11151115
// EXTRA: 次短路
11161116
// 模板题 https://www.luogu.com.cn/problem/P2865
11171117
// LC2045/周赛263D https://leetcode-cn.com/problems/second-minimum-time-to-reach-destination/
1118+
// 次短路径计数 https://www.acwing.com/problem/content/385/
11181119
{
11191120
const inf int64 = 1e18 // 1e9+1
11201121
dist := make([]int64, n)
@@ -1852,6 +1853,103 @@ func (*graph) strictlySecondMST(n int, edges []struct{ v, w, wt int }, min, max
18521853
return mstSum
18531854
}
18541855

1856+
// 曼哈顿距离最小生成树 O(nlogn)
1857+
// LC1584 https://leetcode-cn.com/problems/min-cost-to-connect-all-points/
1858+
// 做法见官方题解 https://leetcode-cn.com/problems/min-cost-to-connect-all-points/solution/lian-jie-suo-you-dian-de-zui-xiao-fei-yo-kcx7/
1859+
func (*graph) manhattanMST(points []struct{ x, y, i int }, abs func(int) int) (mst int) {
1860+
n := len(points)
1861+
// 读入时把 points 加上下标
1862+
1863+
type edge struct{ v, w, dis int }
1864+
edges := []edge{}
1865+
1866+
build := func() {
1867+
sort.Slice(points, func(i, j int) bool { a, b := points[i], points[j]; return a.x < b.x || a.x == b.x && a.y < b.y })
1868+
1869+
// 离散化 y-x
1870+
type pair struct{ v, i int }
1871+
ps := make([]pair, n)
1872+
for i, p := range points {
1873+
ps[i] = pair{p.y - p.x, i}
1874+
}
1875+
sort.Slice(ps, func(i, j int) bool { return ps[i].v < ps[j].v })
1876+
kth := make([]int, n)
1877+
k := 1
1878+
kth[ps[0].i] = k
1879+
for i := 1; i < n; i++ {
1880+
if ps[i].v != ps[i-1].v {
1881+
k++
1882+
}
1883+
kth[ps[i].i] = k
1884+
}
1885+
1886+
const inf int = 2e9
1887+
tree := make([]int, k+1)
1888+
idRec := make([]int, k+1)
1889+
for i := range tree {
1890+
tree[i] = inf
1891+
idRec[i] = -1
1892+
}
1893+
update := func(pos, val, id int) {
1894+
for ; pos > 0; pos &= pos - 1 {
1895+
if val < tree[pos] {
1896+
tree[pos] = id
1897+
idRec[pos] = id
1898+
}
1899+
}
1900+
}
1901+
query := func(pos int) int {
1902+
minVal, minID := inf, -1
1903+
for ; pos < len(tree); pos += pos & -pos {
1904+
if tree[pos] < minVal {
1905+
minVal = tree[pos]
1906+
minID = idRec[pos]
1907+
}
1908+
}
1909+
return minID
1910+
}
1911+
1912+
for i := n - 1; i >= 0; i-- {
1913+
p := points[i]
1914+
pos := kth[i]
1915+
if j := query(pos); j != -1 {
1916+
q := points[j]
1917+
dis := abs(p.x-q.x) + abs(p.y-q.y)
1918+
edges = append(edges, edge{p.i, q.i, dis})
1919+
}
1920+
update(pos, p.x+p.y, i)
1921+
}
1922+
}
1923+
build()
1924+
for i := range points {
1925+
points[i].x, points[i].y = points[i].y, points[i].x
1926+
}
1927+
build()
1928+
for i := range points {
1929+
points[i].x = - points[i].x
1930+
}
1931+
build()
1932+
for i := range points {
1933+
points[i].x, points[i].y = points[i].y, points[i].x
1934+
}
1935+
build()
1936+
1937+
sort.Slice(edges, func(i, j int) bool { return edges[i].dis < edges[j].dis })
1938+
1939+
uf := newUnionFind(n)
1940+
left := n - 1
1941+
for _, e := range edges {
1942+
if uf.merge(e.v, e.w) {
1943+
mst += e.dis // int64
1944+
left--
1945+
if left == 0 {
1946+
break
1947+
}
1948+
}
1949+
}
1950+
return
1951+
}
1952+
18551953
// Kruskal 重构树
18561954
// https://oi-wiki.org/graph/mst/#kruskal_1
18571955

0 commit comments

Comments
 (0)