凸包
首先如果点数小于等于2那么一定是不存在合法情况的
其次是如果所有点共线(并且点数超过3个),那么一定可以
然后做凸包,如果一共就三个点那么一定是不合法,否则就可以判断:
1、如果凸包点数等于n,那么采用 A B 相间的方法就行了
2、如果不等于n,那么凸包上的是A,凸包里面的是B就一定合法
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <math.h>
using namespace std;
const int MAXN = 1010;
struct Point {
double x, y;
int id;
Point(){}
Point(double _x,double _y,int i) { x = _x;y = _y;id = i;}
Point operator -(const Point &b)const { return Point(x - b.x,y - b.y, 0); }
//叉积
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; }
};
double dist(Point a,Point b) { return sqrt((a-b)*(a-b)); }
double eps = 1e-9;
char ans[MAXN];
Point list[MAXN];
int Stack[MAXN], top, n;
int sgn(double x) {
if(fabs(x) < eps)return 0;
if(x < 0)return -1;
else return 1;
}
//相对于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);
if(n == 1) {
top = 1;
Stack[0] = 0;
return;
}
if (n == 2) {
top = 2;
Stack[0] = 0;
Stack[1] = 1;
return ;
}
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;
}
}
bool __cmp(Point p1, Point p2) {
if (p1.x < p2.x) return true;
if (p1.x > p2.x) return false;
return (p1.y < p2.y);
}
bool check() {
sort(list, list+n, __cmp);
for (int i = 2; i < n; i++) {
if (fabs((list[i-2]-list[i-1])^(list[i]-list[i-1])) > eps) return false;
}
return true;
}
int main() {
freopen("input.txt","r",stdin);
int T;
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;
}
if (check()) {
printf("YES\n");
int k = 0;
for (int i = 0; i < n; i++) {
ans[list[i].id] = k==1?'A':'B';
k ^= 1;
}
for (int i = 0; i < n; i++) printf("%c", ans[i]);
printf("\n"); continue;
}
if (n == 3) {
printf("NO\n"); continue;
}
for (int i = 0; i < n; i++) ans[i] = 'B';
Graham(n);
if (top < n) {
for (int i = 0; i < top; i++) ans[list[Stack[i]].id] = 'A';
} else {
for (int i = 0; i < top; i++)
if (i%2) ans[list[Stack[i]].id] = 'A';
}
printf("YES\n");
for (int i = 0; i < n; i++) printf("%c", ans[i]);
printf("\n");
}
}