【NOIP 模拟题】独眼兔(计算几何)

35 篇文章 0 订阅
5 篇文章 0 订阅

独眼兔(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 4

   7 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;
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值