HihoCoder 1582 Territorial Dispute (思维+凸包)

                                      Territorial Dispute

In 2333, the C++ Empire and the Java Republic become the most powerful country in the world. They compete with each other in the colonizing the Mars.

There are n colonies on the Mars, numbered from 1 to n. The i-th colony's location is given by a pair of integers (xi, yi). Notice that latest technology in 2333 finds out that the surface of Mars is a two-dimensional plane, and each colony can be regarded as a point on this plane. Each colony will be allocated to one of the two countries during the Mars Development Summit which will be held in the next month.

After all colonies are allocated, two countries must decide a border line. The Mars Development Convention of 2048 had declared that: A valid border line of two countries should be a straight line, which makes colonies of different countries be situated on different sides of the line.

The evil Python programmer, David, notices that there may exist a plan of allocating colonies, which makes the valid border line do not exist. According to human history, this will cause a territorial dispute, and eventually lead to war.

David wants to change the colony allocation plan secretly during the Mars Development Summit. Now he needs you to give him a specific plan of allocation which will cause a territorial dispute. He promises that he will give you 1000000007 bitcoins for the plan.

 

Input

The first line of the input is an integer T, the number of the test cases (T ≤ 50).

For each test case, the first line contains one integer n (1 ≤ n ≤ 100), the number of colonies.

Then n lines follow. Each line contains two integers xi, yi (0 ≤ xi, yi ≤ 1000), meaning the location of the i-th colony. There are no two colonies share the same location.

There are no more than 10 test cases with n > 10.

Output

For each test case, if there exists a plan of allocation meet David's demand, print "YES" (without quotation) in the first line, and in the next line, print a string consisting of English letters "A" and "B". The i-th character is "A" indicates that the i-th colony was allocated to C++ Empire, and "B" indicates the Java Republic.

If there are several possible solutions, you could print just one of them.

If there is no solution, print "NO".

Sample Input

2
2
0 0
0 1
4
0 0
0 1
1 0
1 1

Sample Output

NO
YES
ABBA

 

一、原题地址

点我传送

 

二、大致题意

给出N个二维坐标上的点,现在要求将他们分成A、B两组,若分组的情况满足:在平面上切一刀,无论如何下刀都不能将A、B完全分到两侧。则输出任意一种将n个点分配到A、B的方案。若存在任意一种方案可以一刀将A、B完全分开则输出NO。

 

三、大致思路

若n<=2那么显然是不存在任意一种分配方式的。n=3时,若构成的是一个三角形,那么显然也不行。其他的情况我们可以先跑一个凸包,

若所有的点都在凸包上,那么只需要在凸包上隔着一个来选择颜色就行(这里也包含了n=3时,三点一条线的情况)。

如果有部分点不在凸包上,那么可以让凸包上所有的点为一种颜色,凸包内的所有点为另一种颜色。

 

四、代码

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;
const int inf = 0x3f3f3f3f;


int T;
const double eps = 1e-8;
const double PI = acos(-1.0);
int sgn(double x)
{
	if (fabs(x) < eps)return 0;
	if (x < 0)return -1;
	else return 1;
}
struct Point
{
	double x, y;
	int id;
	Point() {}
	Point(double _x, double _y)
	{
		x = _x; y = _y;
	}
	Point operator -(const Point &b)const
	{
		return Point(x - b.x, y - b.y);
	}
	//叉积
	double operator ^(const Point &b)const
	{
		return x*b.y - y*b.x;
	}
	//点积
	double operator *(const Point &b)const
	{
		return x*b.x + y*b.y;
	}
	//绕原点旋转角度B(弧度值),后x,y的变化
	void transXY(double B)
	{
		double tx = x, ty = y;
		x = tx*cos(B) - ty*sin(B);
		y = tx*sin(B) + ty*cos(B);
	}
};
const int MAXN = 1010;
Point list[MAXN];
int Stack[MAXN], top;
double dist(Point a, Point b)
{
	return sqrt((a - b)*(a - b));
}
//相对于list[0]的极角排序
bool _cmp(Point p1, Point p2)
{
		double tmp = (p1 - list[0]) ^ (p2 - list[0]);
	if (sgn(tmp) > 0)return true;
	else if (sgn(tmp) == 0 && sgn(dist(p1, list[0]) - dist(p2, list[0])) <= 0)
		return true;
	else return false;
}
void Graham(int n)
{
	Point p0;
	int k = 0;
	p0 = list[0];
	//找最下边的一个点
	for (int i = 1; i < n; i++)
	{
		if ((p0.y > list[i].y) || (p0.y == list[i].y && p0.x > list[i].x))
		{
			p0 = list[i];
			k = i;
		}
	}
	swap(list[k], list[0]);
	sort(list + 1, list + n, _cmp);
	Stack[0] = 0;
	Stack[1] = 1;
	top = 2;
	for (int i = 2; i < n; i++)
	{
		while (top > 1 &&
			sgn((list[Stack[top - 1]] - list[Stack[top - 2]]) ^ (list[i] - list[Stack[top - 2]])) <=
			0)
			top--;
		Stack[top++] = i;
	}
}
int n;
int color[105];
int main()
{
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d", &n);
		for (int i = 0; i < n; i++)
		{
			scanf("%lf %lf", &list[i].x, &list[i].y);
			list[i].id = i;
		}
		if (n <= 2)
		{
			printf("NO\n");
			continue;
		}
		else
		{
			memset(color, 0, sizeof(color));
			Graham(n);
			if (top == 3 && n == 3)
			{
				printf("NO\n");
				continue;
			}
			if (top != n)
			{
				for (int i = 0; i < top; i++)
				{
					color[list[Stack[i]].id] = 1;
				}
			}
			else
			{
				for (int i = 0; i < top; i+=2)
				{
					color[list[Stack[i]].id] = 1;
				}
			}
			printf("YES\n");
			for (int i = 0; i < n; i++)
			{
				if (color[i])printf("A");
				else printf("B");
			}
			printf("\n");
		}
	}
}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值