manhattan最小生成树

//manhattan距离下的最小生成树,主要在于产生有效边,然后对产生的有效边集求最小生成树
//POJ3241
//将N个点奉承K个部分,定义两个点的相似度是他们的曼哈顿距离,找出一个数X使得每个点数大于1的部分任意两个点的相似度都不大于X
//转化成manhattan最小生成树求n-k小边问题,可以想成对于最小生成树里面把大于X的边都切掉形成一部分,这一部分可能只有一个点,也可能得到多个点但是他们的manhattan距离不大于X 
//复杂度O(n*logn)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#include<vector>
#include<map>
using namespace std ;

const int maxn = 1e5 + 10 ;
const int INF = 0x3f3f3f3f ;

struct Point{
    int x, y , id ;
}p[maxn];
//按照x为第一关键字y为第二关键字排序 
bool cmp( Point a , Point b ){
    if( a.x != b.x )
        return a.x < b.x ;
    else
        return a.y < b.y ;
} 
//树状数组,找y-x大于当前的,但是y+x最小的 
struct BIT{
    int min_val , pos ;
    void ini(){
        min_val = INF ;
        pos = -1 ;
    }
}bit[maxn];
//最多4n条有效边而不是n*n 
struct Edge{
    int u, v , d ;
}edge[maxn << 2];

bool cmpedge( Edge a , Edge b){
    return a.d < b.d ;
} 

int tot , n , 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 ;
}


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 ) ;
    }
}
//[i,m]的最小位置 
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 MNST( 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].ini() ;
        } 
        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 ){
    MNST( 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、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值