题目
http://poj.org/problem?id=1696
大概题意就是给一堆点(在第一象限),让你从 y 值最小的最左边那个点开始,一直往左边走,问最多能走多少个点。(下面是个例子)
分析
- 举几个例子就发现好像是全部点都肯定能走道的。
- 那么就从起点开始,每次在剩下的点中选一个在逆时针方向极角最小的点作下一个点即可。
- AC 在 AB 顺时针方向当且仅当 |AB×AC|<0。
程序
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int ans[20000],f[20000],n,T;
struct node{
int id,x,y;} a[20000];
bool cmp(node A,node B){
return A.y<B.y||A.y==B.y&&A.x<B.x;}
int cheng(node v1,node v2){
return v1.x*v2.y-v2.x*v1.y;}
int Dis(node A,node B){
return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y);}
node Vct(node U,node V){
return (node){
0,V.x-U.x,V.y-U.y};}
void dfs(node A,int cnt){
if (cnt>n) return;
node ret;
ans[cnt]=f[A.id]=A.id;
for (int i=1; i<=n; i++) if (!f[a[i].id]) {ret=a[i]; break;}
for (int i=1; i<=n; i++)
if(!f[a[i].id] && (cheng(Vct(A,ret),Vct(A,a[i]))<0 || (cheng(Vct(A,ret),Vct(A,a[i]))==0 && Dis(A,a[i])<Dis(A,ret))))
ret=a[i];
dfs(ret,cnt+1);
}
int main(){
for(scanf("%d",&T); T--;){
memset(f,0,sizeof(f));
scanf("%d",&n);
for (int i=1; i<=n; i++) scanf("%d%d%d",&a[i].id,&a[i].x,&a[i].y);
sort(a+1,a+n+1,cmp);
dfs(a[1],1);
printf("%d ",n);
for (int i=1; i<=n; i++) printf("%d%c",ans[i],i==n?'\n':' ');
}
}
提示
- 注意可能有共线的情况(叉积为0),这时需要取离当前点最近的那个点。