题意:平面上给出n个点,分为黑白两种颜色,问在其中给出一个隔板,使隔板左边+隔板右边的棋子数量最大(左右隔板棋子颜色不同、隔板上的棋子算任意一边)
寒假的第一题,屯了很久没做,自己的思维还是不够做这个题。
枚举每一个点,当做基准点,算出相对坐标,再算出一个极坐标角,用来排序,基准点即可看作是(0,0)再枚举点a与基准点p的直线l1,b与基准点p的直线l2,叉积判断是否在一侧,若超过180以后,将a++,继续枚举下一个b,动态维护。
还有个技巧是将白关于基准点翻转180即是黑。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + 5;
struct Node{
int x;
int y;
int c;
double rad;
Node(){}
}node[maxn],pt[maxn];
bool cmp(Node p, Node q){
return p.rad < q.rad;
}
int cross(Node a, Node c){
//return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
return a.y * c.x - a.x * c.y >= 0;
}
int main(int argc, const char * argv[]) {
int n;
while(cin >> n && n){
int ans = 0;
for(int i=0; i<n; i++){
cin >> node[i].x >> node[i].y >> node[i].c;
}
if(n <= 3) {
cout << n << endl;
continue;
}
for(int i=0; i<n; i++){
int cnt = 0;
for(int j=0; j<n; j++){
if(i == j) continue;
pt[cnt].x = node[j].x - node[i].x;
pt[cnt].y = node[j].y - node[i].y;
if(node[j].c == 1){
pt[cnt].x = -pt[cnt].x;
pt[cnt].y = -pt[cnt].y;
}
pt[cnt].rad = atan2(pt[cnt].y,pt[cnt].x);
cnt++;
}
sort(pt, pt+cnt, cmp);//基准点不在里面 基准点可以看作是0,0
int l = 0, r = 1, sum = 2;
while(l < cnt){
if(r == l){
r = (l+1) % cnt;
sum = 2;
}
while(r != l && cross(pt[r], pt[l])){
sum++;
r = (r+1) % cnt;
}
ans = max(ans,sum);
sum--;
l++;
}
}
cout << ans << endl;
}
}
/*
3
0 0 0
0 1 0
2 2 1
4
0 0 0
0 4 0
4 0 0
1 2 1
7
-1 0 0
1 2 1
2 3 0
2 1 1
0 3 1
1 4 0
-1 2 0
0
*/