Poj3241 Object Clustering

Poj3241 Object Clustering

Position:


List

Description

  • 大意:求曼哈頓距離最小生成樹上第k大(第n-k小)的邊

Knowledge

參考曼哈頓距離最小生成樹
http://blog.csdn.net/yjpyjp2014/article/details/52180707

Solution

分析:
1.由上面資料可知,每45度的範圍只算一個最近點
2.看下面一種情況:
      case
對於下面那個點,上面的點在它的右上方。而它又在上面的點的左下方,故我們只需計算左上和右上,即角[0,180]的範圍,每45度一個,每個點4個,故邊數不超過4×n。
3-1.爲了寫代碼的方便,我們每次將點翻轉,只計算[45,90]範圍的點。翻轉:①第一次不翻②第二次將一個點的x與y交換(即沿y=x翻轉,原本在[0,45]的點翻到了[45,90])③將x=-x,沿x=0翻轉,左上翻到右上④
3-2.ZYT的寫法(可能容易理解一點):我們只需考慮在一塊區域內的點,其他區域內的點可以通過座標變換“移動”到這個區域內。爲了方便處理,我們考慮在y軸向右45度的區域。在某個點A(x0,y0)的這個區域內的點B(x1,y1)滿足x1≥x0且y1-x1>y0-x0。這裏對於邊界我們只取一邊,但是操作中兩邊都取也無所謂。那麼|AB|=y1-y0+x1-x0=(x1+y1)-(x0+y0)。在A的區域內距離A最近的點也即滿足條件的點中x+y最小的點。因此我們可以將所有點按x座標排序,再按y-x離散,用線段樹或者樹狀數組維護大於當前點的y-x的最小的x+y對應的點(也就是維護區間最小值)。時間複雜度O(NlogN)。至於座標變換,一個比較好處理的方法是第一次直接做(R1==R5);第二次沿直線y=x翻轉,即交換x和y座標(R2==R6);第三次沿直線x=0翻轉,即將x座標取相反數(R7==R3);第四次再沿直線y=x翻轉(R8==R4)。注意只需要做4次,因爲邊是雙向的。
             ZYT
4.對於點(x,y)如果有一個點(x1,y1)在它的(45,90),只要滿足y1-x1>y-x(證明:即用一條斜率爲45的直線,過這個點,比截距的大小y=x+b,y-x=b,平面圖知識qaq~)
5.按x座標排序,從後往前掃,值域(y-x)樹狀數組,w記錄的是曼哈頓距離,pos記錄第幾個點。

Notice

1.這是一個反的樹狀數組,c[i]記錄i~i+lowbit(i)-1
2.因爲只要求x~m的最小值,用樹狀數組可以

Code

// <ObjectClustering.cpp> - 08/11/16 16:35:38
// This file is made by YJinpeng,created by XuYike's black technology automatically.
// Copyright (C) 2016 ChangJun High School, Inc.
// I don't know what this program is.

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#define MOD 1000000007
#define INF 1e9
#define EPS 1e-10
using namespace std;
typedef long long LL;
const int MAXN=10010;
const int MAXM=100010;
inline int max(int &x,int &y) {return x>y?x:y;}
inline int min(int &x,int &y) {return x<y?x:y;}
inline int getint() {
    register int w=0,q=0;register char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')q=1,ch=getchar();
    while(ch>='0'&&ch<='9')w=w*10+ch-'0',ch=getchar();
    return q?-w:w;
}
int n,m,k,tot,cnt,x,pos;
int f[MAXN],hs[MAXN],t[MAXN];
struct Point{
    int x,y,id;
    void read(){x=getint();y=getint();}
    friend bool operator < (const Point &a,const Point &b) {
        return a.x==b.x?a.y<b.y:a.x<b.x;
    }
}p[MAXN];
struct Edge{
    int u,v,w;
    friend bool operator < (const Edge &a,const Edge &b){
        return a.w<b.w;
    }
}e[MAXN*4];
struct Bit{
    int w,pos;
    void Pre(){pos=-1,w=INF;}
}b[MAXN];
inline int Find(int x){return x==f[x]?x:f[x]=Find(f[x]);}
inline int Lowbit(int x){return x&(-x);}
int Dis(int a,int b){
    return abs(p[a].x-p[b].x)+abs(p[a].y-p[b].y);
}
int Query(int x){
    int M=INF,pos=-1;
    for(int i=x;i<=m;i+=Lowbit(i))
        if(b[i].w<M)M=b[i].w,pos=b[i].pos;
    return pos;
}
void Update(int x,int M,int pos){
    for(int i=x;i;i-=Lowbit(i))
        if(M<b[i].w)b[i].w=M,b[i].pos=pos;
}
void Insert(int u,int v,int w){
    e[++cnt].u=u;e[cnt].v=v;e[cnt].w=w;
}
void Caledge(){
    sort(p+1,p+1+n);
    for(int i=1;i<=n;i++)hs[i]=t[i]=p[i].y-p[i].x;
    sort(hs+1,hs+1+n);
    m=unique(hs+1,hs+1+n)-hs;
    for(int i=1;i<=m;i++)b[i].Pre();
    for(int i=n;i>=1;i--){
        x=lower_bound(hs+1,hs+1+m,t[i])-hs+1;
        pos=Query(x);
        if(pos!=-1)Insert(p[i].id,p[pos].id,Dis(i,pos));
        Update(x,p[i].x+p[i].y,i);
    }
}
void Kruskal(){
    sort(e+1,e+1+cnt);tot=0;
    for(int i=1;i<=n;i++)f[i]=i;
    for(int i=1;i<=cnt;i++){
        f[e[i].u]=Find(f[e[i].u]);
        f[e[i].v]=Find(f[e[i].v]);
        if(f[e[i].u]!=f[e[i].v])f[f[e[i].u]]=f[e[i].v],tot++;
        if(tot==k){printf("%d",e[i].w);break;}
    }
}
int main()
{
    freopen("ObjectClustering.in","r",stdin);
    freopen("ObjectClustering.out","w",stdout);
    n=getint();k=n-getint();
    for(int i=1;i<=n;i++)p[i].read(),p[i].id=i;
    for(int j=1;j<=4;j++){
        if(j==2||j==4)
            for(int i=1;i<=n;i++)swap(p[i].x,p[i].y);
        else if(j==3)
            for(int i=1;i<=n;i++)p[i].x=-p[i].x;
        Caledge();
    }
    Kruskal();
    return 0;
}

感謝

Friend ZYT的大力支持

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章