POJ--3241(曼哈顿距离,MST)
2015-04-29 21:58:58
题目:题意有先争议... 其实出题人就是想考:求曼哈顿距离最小生成树上的第K大的边。
关于 manhattan mst 的介绍:博客。
然后就是比较裸的问题了... 最后用kruskal找第K大的边。
过程基本上可以简述为:
(1)将所有点经历四种变换【不变,y=x对称,y=0对称,y=x对称】
(2)对于每种变换,要找出每个点在 y 轴向右45度的1/8象限区域内最近的点。
首先对所有点按 x 排序,再把 y- x离散化(若数据大),然后对于每个点用树状数组求出 y-x 比该点大且 x+y 最小的点,两点建边。
(3)根据建的边跑一遍Kruskal,找第 N-K 条边即可。
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <map> #include <set> #include <stack> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define MEM(a,b) memset(a,b,sizeof(a)) #define REP(i,n) for(int i=0;i<(n);++i) #define FOR(i,a,b) for(int i=(a);i<=(b);++i) #define getmid(l,r) ((l) + ((r) - (l)) / 2) #define MP(a,b) make_pair(a,b) #define PB(a) push_back(a) typedef long long ll; typedef pair<int,int> pii; const double eps = 1e-8; const int INF = (1 << 30) - 1; const int MAXN = 10010; int N,K; int fa[MAXN],A[MAXN],B[MAXN]; int ecnt; struct edge{ int u,v,c; bool operator < (const edge a) const{ return c < a.c; } }e[4 * MAXN]; void Add_edge(int u,int v,int c){ e[++ecnt].u = u; e[ecnt].v = v; e[ecnt].c = c; } struct Node{ int x,y,id; bool operator < (const Node a) const{ return x == a.x ? y < a.y : x < a.x; } }p[MAXN]; struct BIT{ int c[MAXN],ps[MAXN],tmax; void init(int tmp){ tmax = tmp; FOR(i,1,tmax) c[i] = INF; MEM(ps,-1); } int lowbit(int x){ return x & (-x); } void update(int x,int d,int pos){ while(x){ if(d < c[x]){ c[x] = d; ps[x] = pos; } x -= lowbit(x); } } int get(int x){ int res = INF,pos = -1; while(x <= tmax){ if(c[x] < res){ res = c[x]; pos = ps[x]; } x += lowbit(x); } return pos; } }bit; int Dis(int a,int b){ return abs(p[a].x - p[b].x) + abs(p[a].y - p[b].y); } int Find(int x){ return fa[x] == x ? x : fa[x] = Find(fa[x]); } int Manhattan_mst(){ for(int dir = 1; dir <= 4; ++dir){ //四种变换:(1) none , (2) y=x , (3) y=0 , (4) y=x if(dir == 2 || dir == 4) FOR(i,1,N) swap(p[i].x,p[i].y); else if(dir == 3) FOR(i,1,N) p[i].y = -p[i].y; sort(p + 1,p + N + 1); //sort by x FOR(i,1,N) A[i] = B[i] = p[i].y - p[i].x; //离散化 sort(B + 1,B + N + 1); int sz = unique(B + 1,B + N + 1) - B - 1; //初始化反树状数组 bit.init(sz); for(int i = N; i >= 1; --i){ //从 x 大的开始考虑 int pos = lower_bound(B + 1,B + sz + 1,A[i]) - B; int ans = bit.get(pos); //比当前 y-x 大的最小 x+y 位置 if(ans != -1) Add_edge(p[i].id,p[ans].id,Dis(i,ans));//i找到匹配ans bit.update(pos,p[i].x + p[i].y,i); } } //Kruskal sort(e + 1,e + ecnt + 1); int cnt = N - K; FOR(i,1,N) fa[i] = i; FOR(i,1,ecnt){ int x = Find(e[i].u); int y = Find(e[i].v); if(x != y){ fa[y] = x; cnt--; if(cnt == 0) return e[i].c; } } } int main(){ while(scanf("%d%d",&N,&K) != EOF){ FOR(i,1,N){ scanf("%d%d",&p[i].x,&p[i].y); p[i].id = i; } ecnt = 0; printf("%d\n",Manhattan_mst()); } return 0; }