【POJ 3241】曼哈顿最小生成树(模板整理)
2015-08-16 21:45
417 查看
关于 曼哈顿最小生成树 的证明见:http://www.2cto.com/kf/201505/399861.html
模板:
模板:
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 100010; const int INF = 0x3f3f3f3f; struct Point{ int x,y,id; }p[MAXN]; bool cmp(Point a,Point b){ if(a.x != b.x) return a.x < b.x; return a.y < b.y; } struct BIT{ int min_val,pos; void init(){ min_val = INF; pos = -1; } }bit[MAXN]; struct Edge{ int u,v,d; }edge[MAXN << 2]; bool cmpedge(Edge a,Edge b){ return a.d < b.d; } int tot; int n; int F[MAXN]; int find(int x){ if(F[x] == -1) return x; else return F[x] = find(F[x]); } void addedge(int u,int v,int d){ edge[tot].u = u; edge[tot].v = v; edge[tot].d = d; tot ++; } int lowbit(int x){ return x & -x; } void update(int i,int val,int pos){ while(i > 0){ if(val < bit[i].min_val){ bit[i].min_val = val; bit[i].pos = pos; } i -= lowbit(i); } } int ask(int i,int m){ int min_val = INF, pos = -1; while(i <= m){ if(bit[i].min_val < min_val){ min_val = bit[i].min_val; pos = bit[i].pos; } i += lowbit(i); } return pos; } int dist(Point a,Point b){ return abs(a.x - b.x) + abs(a.y - b.y); } void Manhattan_minimum_spanning_tree(int n,Point p[]){ int a[MAXN],b[MAXN]; tot = 0; for(int dir = 0;dir < 4; dir++){ 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,cmp); 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; int ans = ask(pos,m); if(ans != -1) addedge(p[i].id,p[ans].id,dist(p[i],p[ans])); update(pos,p[i].x + p[i].y,i); } } } int solve(int k){ Manhattan_minimum_spanning_tree(n,p); memset(F,-1,sizeof(F)); sort(edge,edge + tot,cmpedge); for(int i = 0; i < tot; i++){ int u = edge[i].u; int v = edge[i].v; int t1 = find(u),t2 = find(v); if(t1 != t2){ F[t1] = t2; k --; if(k == 0) return edge[i].d; } } } int main(){ int k; while(scanf("%d%d",&n,&k) == 2 && n){ for(int i = 0; i < n; i++){ scanf("%d%d",&p[i].x,&p[i].y); p[i].id = i; } printf("%d\n",solve(n - k)); } return 0; }
相关文章推荐
- 光场相机 标定微透镜阵列
- 新技术成长型企业往往经过四个发展阶段
- 代理商与经销商的区别
- 泛型 学习记录1
- Java 编程下的二分法查找
- 滑雪(poj 1088)
- 优化SQL语句 2
- Win32汇编--Windows 的内存安排--------2015年9月28日 00:01:54
- 清除缓存功能
- OC基础
- vmware下克隆系统
- android onTouchEvent 左右手势滑动事件处理
- 复制一个Dialog后DoModal()返回-1
- c 语言 逆波兰计算器 C语言程序设计中的例子
- c++继承与派生
- Microsoft Dynamics server 2015 所有的SQL server 2012 视图 介绍及功能
- Microsoft Dynamics server 2015 所有的SQL server 2012 视图 介绍及功能
- linux shell 管道命令(pipe)使用及与shell重定向区别
- hdu 1507 Uncle Tom's Inherited Land* (二分匹配)
- POJ 1942 Paths on a Grid