【NOIP 模拟题】独眼兔(计算几何)
独眼兔(aneye.cpp)
【问题描述】
太郎有一只特殊的兔子,他只有一只左眼,所以当他移动时是不能向右移动的。一天,太郎跟独眼兔做一个游戏,太郎在平面内放了N个萝卜,每个萝卜有一个坐标(xi,yi),且任意两个萝卜不在同一位置。设萝卜A(xi,yi)的yi是所有萝卜中最小的,那么独眼兔从(0,yi)出发,走向萝卜A,然后开始吃萝卜。当他吃完一个萝卜后,会选择下一个萝卜为目标,然后径直向萝卜走去,当然他移动时是不能向右转弯的。独眼兔还有一个特点,他走过的路径上会留下特殊的气味,所以独眼兔不希望他将要走的路与前面走的路相交。太郎想知道独眼兔如何才能吃到最多的萝卜。
【问题输入】
第一行是个整数N;接下来N行,每行两个整数,第i+1行表示第i号萝卜的位置(xi,yi)。
【问题输出】
一行,输出最多能吃到的萝卜数,后面输出吃萝卜的顺序。
【样例输入】
10
4 5
9 8
5 9
1 7
3 2
6 3
10 10
8 1
2 47 6
【样例输出】
10 8 7 3 4 9 5 6 2 1 10
【数据范围】
40%的数据:n<=100;
100%数据:n<=1000,xi<=10000,yi<=10000
_______________________________________________________________________________________
【题解】【计算几何】
【通过分析题目可知,如果行走路线得当,所有萝卜都能吃到。】
【所以,在找下一个点的时候,要保证有尽量多的点在当前点的逆时针方向,依据这个条件不停更新。判断用叉积】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct data{
int x,y;
}a[1010];
int ans[1010],num;
int n;
bool p[1010];
inline int dis(data a,data b)
{
int x=a.x-b.x,y=a.y-b.y;
return (x*x+y*y);
}
inline int cj(data a,data b,data c)
{
return (a.x-c.x)*(b.y-c.y)-(a.y-c.y)*(b.x-c.x);
}
int main()
{
freopen("aneye.in","r",stdin);
freopen("aneye.out","w",stdout);
int i,j,k;
scanf("%d",&n);
num=1;
for(i=1;i<=n;++i)
{
scanf("%d%d",&a[i].x,&a[i].y);
if(a[i].y<a[num].y) num=i;
p[i]=0;
}
p[num]=1; ans[1]=num;
for(i=2;i<=n;++i)
{
j=1;
while(p[j]) ++j;
k=j+1;
while(k<=n)
{
if(!p[k])
{
int t=cj(a[k],a[j],a[ans[i-1]]);
if(t>0||!t&&(dis(a[k],a[ans[i-1]])<dis(a[j],a[ans[i-1]])))
j=k;
}
++k;
}
p[j]=1; ans[i]=j;
}
printf("%d ",n);
for(i=1;i<=n;++i) printf("%d ",ans[i]);
printf("\n");
return 0;
}