uva 1606 (思维+极坐标扫描线)

题意:平面上给出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
 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值