曼哈顿最小生成树

#define _CRT_SECURE_NO_DEPRECATE
#include <iostream>
#include <cstdio>
#include <algorithm>
#define lowbit(x) (x&(-x))
using namespace std;
const int N = 100005;
struct Point{
	int x, y, id;//点坐标
	bool operator<(const Point p)const{
		return x != p.x ? x<p.x : y<p.y;
	}
}p[N];
struct BIT{
	int min_val, pos;
	void init(){
		min_val = (1 << 30);
		pos = -1;
	}
}bit[N];
struct Edge{
	int u, v, d;//边上的点u,v,代价d
	bool operator<(const Edge e)const{
		return d<e.d;
	}
}e[N << 2];
int n, tot, pre[N];
int find(int x){
	return pre[x] = (x == pre[x] ? x : find(pre[x]));
}
int dist(int i, int j){//曼哈顿距离
	return abs(p[i].x - p[j].x) + abs(p[i].y - p[j].y);
}
void addedge(int u, int v, int d){
	e[tot].u = u;
	e[tot].v = v;
	e[tot++].d = d;
}
void update(int x, int val, int pos){
	for (int i = x; i >= 1; i -= lowbit(i))
		if (val<bit[i].min_val)
			bit[i].min_val = val, bit[i].pos = pos;
}
int ask(int x, int m){
	int min_val = (1 << 30), pos = -1;
	for (int i = x; i <= m; i += lowbit(i))
		if (bit[i].min_val<min_val)
			min_val = bit[i].min_val, pos = bit[i].pos;
	return pos;
}
int Manhattan_minimum_spanning_tree(int n, Point *p){
	int a[N], b[N];
	for (int dir = 0; dir<4; dir++){
		//4种坐标变换
		if (dir == 1 || dir == 3){
			for (int i = 0; i<n; i++)
				swap(p[i].x, p[i].y);
		}
		else if (dir == 2){
			for (int i = 0; i<n; i++){
				p[i].x = -p[i].x;
			}
		}
		sort(p, p + n);
		for (int i = 0; i<n; i++){
			a[i] = b[i] = p[i].y - p[i].x;
		}
		sort(b, b + n);
		int m = unique(b, b + n) - b;
		for (int i = 1; i <= m; i++)
			bit[i].init();
		for (int i = n - 1; i >= 0; i--){
			int pos = lower_bound(b, b + m, a[i]) - b + 1;   //BIT中从1开始
			int ans = ask(pos, m);
			if (ans != -1)
				addedge(p[i].id, p[ans].id, dist(i, ans));
			update(pos, p[i].x + p[i].y, i);
		}
	}
	//计算最小生成树【Krusal算法】,返回花费
	int cost = 0;
	sort(e, e + tot);
	for (int i = 0; i<n; i++)
		pre[i] = i;
	for (int i = 0; i<tot; i++){
		int u = e[i].u, v = e[i].v;
		int fa = find(u), fb = find(v);
		if (fa != fb){
			//选中对应边u,v【非同一个连通分量】,权值d
			cost += e[i].d;
			pre[fa] = fb;
		}
	}
	return cost;
}
int main(){
	while (scanf("%d", &n) != EOF&&n)
	{
		tot = 0;//初始化边数为0
		for (int i = 0; i<n; i++)//输入n个点的坐标
		{
			scanf("%d%d", &p[i].x, &p[i].y);
			p[i].id = i;
		}
		//求n各点对应曼哈顿最小生成树的代价
		printf("%d\n", Manhattan_minimum_spanning_tree(n, p));
	}
	return 0;
}

你可能感兴趣的:(曼哈顿最小生成树)