uva1606

第一次看到这个题,想到的是搜索扫描,枚举直线方程,再对每个点去扫,55–这真的很菜鸟把
看dl博客,知道原来这是一个数学题,兴奋,用到了高数学的数学知识诶,我其实还没有做过关于数学的题呢。
https://morslin.github.io/2019/02/14/uva1606-AmphiphilicCarbonMolecules/#正解
超喜欢上面这个dl的博客风格,真的超喜欢,从它的代码里理了一个解题思路
1.把n个点存起来,把每个点都作为一个坐标原点进行枚举,这也就意味着每个点的坐标会随着坐标原点的变化而变化,利用相对坐标原理和atan2函数,建立极坐标。
2.对每个点建立坐标后,也对新得到的点根据极角大小去排序,这是为了方便下面第3步。
3.想像一下,这时就是一根杆在绕着原点一直转,经过一个点,就确定一个直线情况,得到这个情况下的ans,那么这个直线的枚举情况就是从第一个点枚举到最后一个点。由于已经排好序了,这一半是a个,那么另一半就是n-a个,再分别对这两半去统计得ans。这里博主很巧妙运用了 %
while(R != L && flag(a[L], a[R])) R = (R%tot) + 1, ++ans;

但是自己写的时候,发现博主有个更大的智慧,它进行了一个优化,如果没有那个优化,按我上面想的那样子,那么对一个点建立坐标后,又不断枚举每一个点确定一个直线的状况,那么也就是nnn,但是事实上每一因为直线的改变,不用重新枚举点,实际上是减去原来那个点,再加上新增加的范围内的点。这是第一个优化点。
第2个优化点,是博主把黑色的点的坐标都乘上-1,如此就使得原来要统计2边的黑白相加的最大值,现在相当于把对面的黑变成了这边的白。
而在判断是不是同一边,博主利用的是叉乘,因为
a ⃗ ⋅ b ⃗ = ∣ a ∣ ∗ ∣ b ∣ ∗ s i n θ = a x ∗ b y − a y ∗ b x \vec{a} \cdot \vec{b}=|a|*|b|*sin\theta=a_x*b_y-a_y*b_x a b =absinθ=axbyaybx
可以知道,如果 如果叉乘小于0,那么差角就大于180度,那么就是在另一边。

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=1e3+10;
struct re{
int x,y,col;};
re all[maxn];
struct point{
double angle;
int col,x,y;
bool operator< (const point &a) const{return angle<=a.angle;}  };
int n,ans;
point now[maxn];
int judge(int a,int b){if(a==b)return -1;if(a-b>0)return 1;else return 0;}
void made(int a)
{
    int k=0;
    for(int i=1;i<=n;i++)
        if(i!=a)
    {
        now[++k].x=all[i].x-all[a].x;
        now[k].y=all[i].y-all[a].y;
       if(all[i].col)now[k].y*=-1,now[k].x*=-1;
        now[k].angle=atan2(now[k].y,now[k].x);
    }
    sort(now+1,now+n);
    int le=1,re=1,tem=1;//tem =1代表的是作为原点的那个点被记入其中。
 while(le<k)
 {
     if(le==re){re=re%k+1;tem++;}
     while(le!=re&&judge(now[re].y*now[le].x,now[re].x*now[le].y)){re=re%k+1;tem++;}
     ans=max(tem,ans);
     le++;tem--;
 }

}
int main(void)
{
    while(scanf("%d",&n)&&n)
    {
        ans=0;
        for(int i=1;i<=n;i++)
            scanf("%d %d %d",&all[i].x,&all[i].y,&all[i].col);
        for(int i=1;i<=n;i++)
            made(i);
            printf("%d\n",ans);
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是Mally呀!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值