hdu 3952

                                               Fruit Ninja
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 841 Accepted Submission(s): 384
    
Problem Description
Fruit Ninja is a popular classic game. During the game, fruits will up to the air, and your aim is cut as more fruits as possible with a line
 
Even if the line touch a point of a fruit, the fruit also be cut.
Input
The first line is a number T(1<=T<=30), represents the number of case. The next T blocks follow each indicates a case.
The first line of each case contains one integer N (1<=N<=10)
Then N lines follow, each line contains a integer K(3<=K<=10), represent the number points of the fruit, then K*2 integers follow, each two integers represent one point of the fruit.(with anticlockwise order)
I promise all fruits are convex polygon, and any two fruit have no common point. 
Output
For each case, output the number of case and the maximum fruits you could cut with a line.(as shown in the sample output)
Sample Input
2 3 3 0 0 1 0 1 1 3 1 2 2 1 2 2 3 3 1 3 0 4 0 3 4 0 0 1 0 1 1 0 1 4 2 0 3 0 3 1 2 1 4 0 99 1 99 1 100 0 100
Sample Output
Case 1: 3 Case 2: 2
Author
NotOnlySuccess
Source
2011 Alibaba Programming Contest 


任意选取两个水果,并选出水果上两个端点组成一条直线去切割其他的水果,就是判断直线与线段是否相交(n^3*k^3)
注意:每个水果用一个凸多边形来表示。
这题是让你求一条线能够穿过最多的水果(碰到一个点也算)。
可以证明,枚举两个点组成的线是可行的。
因为假设有一条线穿过N个水果,那么把它平移一些使得还是穿过N个但是已经不能再平移了,这样的话,这条线肯定是在某个水果的某个端点上。
再以这个端点,旋转这条线,还是穿过N个,直到不能旋转为止(再旋转可能就不能穿过N个了),这样的话,肯定还是这条线碰到了另外一个端点。
所以只要枚举两个端点即可。
只有一个水果的话,特判下。

代码:
#include<stdio.h>
#define N 20
struct node
{
	int x[N],y[N],sum;
}p[N];
int multi(int x1,int y1,int x2,int y2,int x0,int y0)
{
	return ((x1-x0)*(y2-y0)-(x2-x0)*(y1-y0));
}
int main()
{
	int t,cnt=1,max,i,j,k,q,l,r,ans,n,t1,t2;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		for(i=0;i<n;i++)
		{
			scanf("%d",&p[i].sum);
			for(j=0;j<p[i].sum;j++)
				scanf("%d%d",&p[i].x[j],&p[i].y[j]);
		}
		if(n==1)//注意n=1的情况
		{
		   printf("Case %d: %d\n",cnt++,1);
			continue;
		}
		max=-1;
		for(i=0;i<n;i++)
		{
			for(j=i+1;j<n;j++)
			{
				for(k=0;k<p[i].sum;k++)
				{
					for(l=0;l<p[j].sum;l++)
					{
						ans=2;
						for(q=0;q<n;q++)
						{
							if(q==i||q==j)
								continue;
							for(r=0;r<p[q].sum-1;r++)
							{//判断直线是否与线段相交
							t1=multi(p[i].x[k],p[i].y[k],p[j].x[l],p[j].y[l],p[q].x[r],p[q].y[r]);
                 t2=multi(p[i].x[k],p[i].y[k],p[j].x[l],p[j].y[l],p[q].x[r+1],p[q].y[r+1]);
								if(t1*t2<=0)
								{
									ans++;
									break;
								}
							}
						}
							if(ans>max)
								max=ans;
					}
				}
			}
		}
	printf("Case %d: %d\n",cnt++,max);
	}
	return 0;
}


								
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值