曼哈顿最小距离生成树(poj 3241&& UVALive 3662)

poj 3241 http://poj.org/problem?id=3241

求曼哈顿距离最小生成树第K长的边的长度

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>
#include <vector>
#include <queue>

#define MEM(a,x) memset(a,x,sizeof a)
#define eps 1e-8
#define MOD 10009
#define MAXN 100010
#define MAXM 100010
#define INF 99999999
#define ll __int64
#define bug cout<<"here"<<endl
#define fread freopen("ceshi.txt","r",stdin)
#define fwrite freopen("out.txt","w",stdout)

using namespace std;

int Read()
{
    char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    int x = 0;
    while (c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x;
}

void Print(int a)
{
     if(a>9)
         Print(a/10);
     putchar(a%10+'0');
}

struct Point
{
    int x,y,id;
}p[MAXN];
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 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;
}
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 Manhattan_minmum_spanning_tree(int n,Point p[])
{
    int a[MAXN],b[MAXN];
    tot=0;
    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,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_minmum_spanning_tree(n,p);
    MEM(F,-1);
    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()
{
//    fread;
    int k;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        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;
}

UVALive 3662  http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=23379

求曼哈顿距离最小生成树中边的权值和

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>
#include <vector>
#include <queue>

#define MEM(a,x) memset(a,x,sizeof a)
#define eps 1e-8
#define MOD 10009
#define MAXN 100010
#define MAXM 100010
#define INF 99999999
#define ll long long
#define bug cout<<"here"<<endl
#define fread freopen("ceshi.txt","r",stdin)
#define fwrite freopen("out.txt","w",stdout)

using namespace std;

int Read()
{
    char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    int x = 0;
    while (c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x;
}

void Print(int a)
{
     if(a>9)
         Print(a/10);
     putchar(a%10+'0');
}

struct Point
{
    int x,y,id;
}p[MAXN];
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 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;
}
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 Manhattan_minmum_spanning_tree(int n,Point p[])
{
    int a[MAXN],b[MAXN];
    tot=0;
    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,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);
        }
    }
}

ll solve()
{
    Manhattan_minmum_spanning_tree(n,p);
    MEM(F,-1);
    sort(edge,edge+tot,cmpedge);
    ll ans=0;
    for(int i=0;i<tot;i++)
    {
        int u=edge[i].u;
        int v=edge[i].v;
        int t1=find(u),t2=find(v);
        int k=0;
        if(t1!=t2)
        {
            F[t1]=t2;
            ans+=(ll)edge[i].d;
//            k++;
//            if(k==n-1)
//                break;//加上也可以。。。
        }
    }
    return ans;
}

int main()
{
//    fread;
    int cs=1;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0) break;
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&p[i].x,&p[i].y);
            p[i].id=i;
        }
        printf("Case %d: Total Weight = ",cs++);
        printf("%lld\n",solve());
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值