题目链接:
题目大意:
给 n n 个点,可将这些点分为 两个点集。如果存在一种分配方案,无论怎么划线,都不能使得直线一侧全是 A A ,另一侧全是 ,则输出 YES Y E S 。否则输出 NO N O 。(多组)
数据范围:
T≤501≤n≤1000≤xi,yi≤1000 T ≤ 50 1 ≤ n ≤ 100 0 ≤ x i , y i ≤ 1000
解题思路:
分情况讨论:
n≤2
n
≤
2
时,都是
NO
N
O
;
n==3
n
==
3
时,不共线,则
NO
N
O
,共线则
YES
Y
E
S
;
n>3
n
>
3
时,肯定是
YES
Y
E
S
。
其实吧!求个凸包就可以了。
对于一般情况,所有点不在一条直线上,如果凸包里面还有点,就把凸包上的点分为
A
A
,凸包里面的点分为 就好了;如果凸包里面没有点,随便找图报上两个不相邻的点分为
A
A
,其他的分为 就好了。
如果所有的点都在直线上,找两个不相邻的点分为
A
A
,其余分为 。
其实,求凸包的时候稍作修改,写起来判断就不用那么麻烦了。如果所有点都在一条直线上,修改过的凸包只求出两端的点,这样就相当于凸包里面有点了,不用单独去判断了。
详见代码:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long LL;
const int inf = 1 << 30;
const LL INF = 1LL << 60;
const int MaxN = 105;
const double eps = 1e-6;
int T;
int n, top;
struct Point {
int x, y;
int id;
Point () {}
Point (int a, int b) {
x = a; y = b;
}
bool friend operator < (const Point a, const Point b) {
if(a.y == b.y) return a.x < b.x;
else return a.y < b.y;
}
bool friend operator == (const Point a, const Point b) {
return (a.x == b.x) && (a.y == b.y);
}
Point friend operator + (const Point a, const Point b) {
return Point(a.x + b.x, a.y + b.y);
}
Point friend operator - (const Point a, const Point b) {
return Point(a.x - b.x, a.y - b.y);
}
}PP[MaxN + 5];
Point hull[MaxN + 5]; //放凸包的数组
typedef Point Vector; //这里偷了个小懒
double dis(Point A, Point B) {
return sqrt(1.0 * ((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y)));
}
int Cross(Vector A, Vector B) { //向量叉积
return A.x * B.y - A.y * B.x;
}
bool Gcmp(Point A, Point B) {
Point O = PP[1];
int tmp = Cross(Vector(A - O), Vector(B - O));
if(tmp == 0) {
if(dis(A, PP[1]) < dis(B, PP[1])) return 1;
else return 0;
}
else {
if(tmp > 0) return 1;
else return 0;
}
}
void Graham() {
sort(PP + 1, PP + n + 1);
sort(PP + 1 + 1, PP + n + 1, Gcmp);
hull[1] = PP[1];
hull[2] = PP[2];
top = 2;
for(int i = 3; i <= n; i++) {
//修改就在这个<=上
while(top >= 2 && Cross((PP[i] - hull[top - 1]), (PP[i] - hull[top])) <= 0) top--;
hull[++top] = PP[i];
}
}
//=====================================================
bool vis[MaxN + 5];
bool cmpid(Point A, Point B) {
return A.id < B.id;
}
int main()
{
scanf("%d", &T);
while(T--)
{
top = 0;
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d %d", &PP[i].x, &PP[i].y);
PP[i].id = i;
}
Graham();
if(n <= 2) printf("NO\n");
else if(n == 3 && top == n) printf("NO\n");
else {
if(top == n) {
vis[hull[1].id] = 1;
vis[hull[3].id] = 1;
}
else if(top < n) {
for(int i = 1; i <= top; i++)
vis[hull[i].id] = 1;
}
sort(PP + 1, PP + n + 1, cmpid);
printf("YES\n");
for(int i = 1; i <= n; i++) {
if(vis[PP[i].id] == 1) printf("A");
else printf("B");
}
printf("\n");
//for(int i = 1; i <= top; i++)
// printf("%d %d\n", hull[i].x, hull[i].y);
}
memset(vis, 0, sizeof(vis));
}
return 0;
}