您的位置:首页 > 其它

POJ 3241 曼哈顿最小生成树

2015-10-09 13:12 441 查看
感觉讲解,写的非常详细,http://blog.csdn.net/huzecong/article/details/8576908

重点是一个定理: Hint For the graph on the right, there exists a minimum spanning tree in which there is at most one vertex connected with A in the shadow area. You can extend this property to solve the problem.

#include<cstdio>
#include<algorithm>
#define N 100010
#define INF 0x3f3f3f3f

using namespace std;

struct point
{
int x,y,id;
bool operator<(const point &p) const
{ return x==p.x?y<p.y:x<p.x;}
}p
;
struct edge
{
int a,b,w;
bool operator<(const edge &x) const
{ return w<x.w;}
}e[N<<2];
struct BIT
{
int w,p;
}bit
;

int n,k,m,tot,ans;
int f
,a
,b
;

int abs(int x)
{
return x<0?-x:x;
}

int find(int x)
{
return x==f[x]?x:f[x]=find(f[x]);
}

int query(int x)
{
int r=INF,p=-1;
while(x<=m)
{
if (bit[x].w<r) r=bit[x].w,p=bit[x].p;
x+=x&-x;
}
return p;
}

void update(int x, int w, int p)
{
while(x>0)
{
if (bit[x].w>w) bit[x].w=w,bit[x].p=p;
x-=x&-x;
}
}

void addedge(int a, int b, int w)
{
++tot;
e[tot].a=a,e[tot].b=b,e[tot].w=w;
}

int dist(point a, point b)
{
return abs(a.x-b.x)+abs(a.y-b.y);
}

int main()
{
while(scanf("%d%d",&n,&k)!=EOF)
{
tot=0;
for (int i=1;i<=n;i++)
{
scanf("%d%d",&p[i].x,&p[i].y);
p[i].id=i;
}
for (int dir=1;dir<=4;dir++)
{
if (dir==2||dir==4)
for (int i=1;i<=n;i++) swap(p[i].x,p[i].y);
else  if (dir==3)
for (int i=1;i<=n;i++) p[i].x=-p[i].x;
sort(p+1,p+n+1);

for (int i=1;i<=n;i++) a[i]=b[i]=p[i].y-p[i].x;
sort(b+1,b+1+n);
m=unique(b+1,b+1+n)-b-1;
for (int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+m+1,a[i])-b;

for (int i=1;i<=m;i++) bit[i].w=INF,bit[i].p=-1;
for (int i=n;i>=1;i--)
{
int pos=query(a[i]);
if (pos!=-1) addedge(p[i].id,p[pos].id,dist(p[i],p[pos]));
update(a[i],p[i].x+p[i].y,i);
}
}
sort(e+1,e+tot+1);
for (int i=1;i<=n;i++) f[i]=i;
for (int i=1,ec=n;ec>k&&i<=tot;i++)
if (find(e[i].a)!=find(e[i].b))
{
f[find(e[i].a)]=find(e[i].b);
if (--ec==k) ans=e[i].w;
}
printf("%d\n",ans);
}
return 0;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: