题目链接:http://codeforces.com/problemset/problem/197/E
题意:给你一棵n个点的树和n个直角坐标系上的点,现在要把树上的n个点映射到直角坐标系的n个点中,要求是除了在顶点处不能有线段的相交。
You are given a tree with n vertexes and n points on a plane, no three points lie on one straight line.
Your task is to paint the given tree on a plane, using the given points as vertexes.
That is, you should correspond each vertex of the tree to exactly one point and each point should correspond to a vertex. If two vertexes of the tree are connected by an edge, then the corresponding points should have a segment painted between them. The segments that correspond to non-adjacent edges, should not have common points. The segments that correspond to adjacent edges should have exactly one common point.
Input
The first line contains an integer n (1 ≤ n ≤ 1500) — the number of vertexes on a tree (as well as the number of chosen points on the plane).
Each of the next n - 1 lines contains two space-separated integers ui and vi (1 ≤ ui, vi ≤ n, ui ≠ vi) — the numbers of tree vertexes connected by the i-th edge.
Each of the next n lines contain two space-separated integers xi and yi ( - 109 ≤ xi, yi ≤ 109) — the coordinates of the i-th point on the plane. No three points lie on one straight line.
It is guaranteed that under given constraints problem has a solution.
Output
Print n distinct space-separated integers from 1 to n: the i-th number must equal the number of the vertex to place at the i-th point (the points are numbered in the order, in which they are listed in the input).
If there are several solutions, print any of them.
Examples
Input
3
1 3
2 3
0 0
1 1
2 0
Output
1 3 2
Input
4
1 2
2 3
1 4
-1 -2
3 5
-3 3
2 0
Output
4 2 1 3
Note
The possible solutions for the sample are given below.
[外链图片转存失败(img-N9ZDridJ-1568001269754)(https://vj.e949.cn/1393d68e352392e8df5e96273e5f31e2?v=1549972047)][外链图片转存失败(img-xOQ8Pl2F-1568001269755)(https://vj.e949.cn/0837595ef0b4cbb2b7dfbb94c8c69f70?v=1549972047)]
极角排序+贪心
我们先选一个在直角坐标系中的最左下角的点,把根结点放到这个点中,然后对剩下的点进行极角排序,按逆时针顺序处理。
如图所示:(该图来自网络)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2000;
struct node
{
int to,nxt;
}edge[2*N];
struct point
{
int x,y,id;
}p[N],poi;
int n,head[2*N],tot=0,ans[N],size[N];
void add(int u,int v)
{
edge[++tot].to=v;
edge[tot].nxt=head[u];
head[u]=tot;
}
bool cmp(point a,point b)//判断极角大小
{
int ax=a.x-poi.x;
int ay=a.y-poi.y;
int bx=b.x-poi.x;
int by=b.y-poi.y;
if (ax>=0 && bx<=0) return true;
if (ax<=0 && bx>=0) return false;
return ax*by>ay*bx;
}
void dfs_size(int u,int fa)//预处理子树大小
{
size[u]=1;
for (int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if (v==fa) continue;
dfs_size(v,u);
size[u]+=size[v];
}
}
void dfs(int l,int r,int u,int fa)
{
int x=l;
for (int i=l+1;i<=r;i++)
{
if (p[i].x<p[x].x || (p[i].x==p[x].x && p[i].y<p[x].y)) x=i;//找到p[i] (l<=i<=r)中最左下角的点
}
swap(p[l],p[x]);
ans[p[l].id]=u;//记录答案
poi=p[l];
sort(p+l+1,p+r+1,cmp);//极角排序
int now=l+1;
for (int i=head[u];i;i=edge[i].nxt)//搜索子树
{
int v=edge[i].to;
if (v==fa) continue;
dfs(now,now+size[v]-1,v,u);
now+=size[v];
}
}
signed main()
{
memset(head,0,sizeof(head));
scanf("%lld",&n);
for (int i=1,u,v;i<=n-1;i++)
{
scanf("%lld%lld",&u,&v);
add(u,v);
add(v,u);
}
for (int i=1;i<=n;i++)
{
scanf("%lld%lld",&p[i].x,&p[i].y);
p[i].id=i;
}
dfs_size(1,0);
dfs(1,n,1,0);
for (int i=1;i<=n;i++)
{
printf("%lld ",ans[i]);
}
return 0;
}