UVA 11704 - Caper pizza

这题UVA只有50+人过,有那么难么。。。

过了之后成功垫底。。

Total Submissions Users that tried itUsers that solved it
264 70 58
Your best accepted try
Ranking SubmissionRun Time LanguageSubmission Date
  54 9156103             0.640        C++  2011-08-16 08:46:46


这题感觉也算经典题了吧,给你两个集合的点,让你求一条线把这些点分成两部分,使得每一部分都包含每个集合点的一半。

这个问题也简化了不少,这条线必须过0,0点,没有三点共线。

没有三点共线这个条件好啊~~~方便了好多。

本来想啊,给了两点之间角度在1e-6一下,难道要枚举角度么?后来想了想,完全没必要,角度还有浮点误差的 = =、、

直接极角排序后,从第一个点找到对称的不和第一个点在一个半区域的那个点,然后一个一个往下扫描,如下图,圈圈画起来的点是第一条扫描线分起来的区域。。额,这个直接满足题意了。如果不满足的话,就按顺序依次扫描。WA了一次,因为对面的那个点是可能再次回到起点的。需要%n。



#include <map>
#include <set>
#include <queue>
#include <stack>
#include <math.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <string>
#include <algorithm>
#define MID(x,y) ( ( x + y ) >> 1 )
#define L(x) ( x << 1 )
#define R(x) ( x << 1 | 1 )
#define BUG puts("here!!!")
#define STOP system("pause")

using namespace std;

const int MAX = 30010;
struct point{double x,y; bool flag;};
point p[MAX];
point s;
const double eps = 1e-8;
bool dy(double x,double y)	{	return x > y + eps;}	// x > y 
bool xy(double x,double y)	{	return x < y - eps;}	// x < y 
bool dyd(double x,double y)	{ 	return x > y - eps;}	// x >= y 
bool xyd(double x,double y)	{	return x < y + eps;} 	// x <= y 
bool dd(double x,double y) 	{	return fabs( x - y ) < eps;}  // x == y
double crossProduct(point a,point b,point c)//向量 ac 在 ab 的方向 顺时针是正 
{
	return (c.x - a.x)*(b.y - a.y) - (b.x - a.x)*(c.y - a.y);
}
bool cmp(point a,point b)
{
	double a1 = atan2(a.y, a.x);
	double a2 = atan2(b.y, b.x);
	return xy(a1, a2);
}
bool solve(int n,int a,int b)
{
	a /= 2; b /= 2;
	point beg = p[0];
	int ca = 0, cb = 0;
	if( p[0].flag == true )
		ca++;
	else
		cb++;
	int i;
	bool flag = false;
	for(i=1; i<n; i++)
	{
		if( xy(crossProduct(s, beg, p[i]), 0.0) )
		{
			if( p[i].flag == true )
				ca++;
			else
				cb++;
		}
		else
		{
			flag = true;
			break;
		}
	}
	
	if( !flag ) i = 0;
	if( ca == a && cb == b ) return true;
	
	for(int k=1; k<n; k++)
	{
		if( p[k-1].flag == true )
			ca--;
		else
			cb--;
		while( xy(crossProduct(s, p[k], p[i]), 0.0) )
		{
			if( p[i].flag )
				ca++;
			else
				cb++;
			i++;
			i %= n;
		}
		if( ca == a && cb == b ) return true;
	}
	return false;
}	

int main()
{
	int a,b;
	s.x = s.y = 0;
	while( ~scanf("%d%d",&a, &b) )
	{
		if( a == b && a == -1 ) break;
		
		int n = 0;
		for(int i=0; i<a; i++)
		{
			scanf("%lf%lf",&p[n].x, &p[n].y);
			p[n++].flag = 1;
		}
		for(int i=0; i<b; i++)
		{
			scanf("%lf%lf",&p[n].x, &p[n].y);
			p[n++].flag = 0;
		}
		
		sort(p, p+n, cmp);	
		
		bool ans = solve(n, a, b);	
		
		if( ans )
			printf("YES\n");
		else
			printf("NO\n");
	}

return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值