【高效算法设计——扫描法】Amphiphilic Carbon Molecules 极角排序

Time Limit: 3000MS Memory Limit: Unknown 64bit IO Format: %lld & %llu

 Status

Description

Download as PDF

Shanghai Hypercomputers, the world's largest computer chip manufacturer, has invented a new class of nanoparticles called Amphiphilic Carbon Molecules (ACMs). ACMs are semiconductors. It means that they can be either conductors or insulators of electrons, and thus possess a property that is very important for the computer chip industry. They are also amphiphilic molecules, which means parts of them are hydrophilic while other parts of them are hydrophobic. Hydrophilic ACMs are soluble in polar solvents (for example, water) but are insoluble in nonpolar solvents (for example, acetone). Hydrophobic ACMs, on the contrary, are soluble in acetone but insoluble in water. Semiconductor ACMs dissolved in either water or acetone can be used in the computer chip manufacturing process.

As a materials engineer at Shanghai Hypercomputers, your job is to prepare ACM solutions from ACM particles. You go to your factory everyday at 8 am and find a batch of ACM particles on your workbench. You prepare the ACM solutions by dripping some water, as well as some acetone, into those particles and watch the ACMs dissolve in the solvents. You always want to prepare unmixed solutions, so you first separate the ACM particles by placing an Insulating Carbon Partition Card (ICPC) perpendicular to your workbench. The ICPC is long enough to completely separate the particles. You then drip water on one side of the ICPC and acetone on the other side. The ICPC helps you obtain hydrophilic ACMs dissolved in water on one side and hydrophobic ACMs dissolved in acetone on the other side. If you happen to put the ICPC on top of some ACM particles, those ACMs will be right at the border between the water solution and the acetone solution, and they will be dissolved. Fig.1 shows your working situation.

\epsfbox{p3259a.eps}

Fig.1

Your daily job is very easy and boring, so your supervisor makes it a little bit more challenging by asking you to dissolve as much ACMs into solution as possible. You know you have to be very careful about where to put the ICPC since hydrophilic ACMs on the acetone side, or hydrophobic ACMs on the water side, will not dissolve. As an experienced engineer, you also know that sometimes it can be very difficult to find the best position for the ICPC, so you decide to write a program to help you. You have asked your supervisor to buy a special digital camera and have it installed above your workbench, so that your program can obtain the exact positions and species (hydrophilic or hydrophobic) of each ACM particle in a 2D pictures taken by the camera. The ICPC you put on your workbench will appear as a line in the 2D pictures.

\epsfbox{p3259b.eps}

Fig.2

Input 

There will be no more than 10 test cases. Each case starts with a line containing an integer N, which is the number of ACM particles in the test case. N lines then follow. Each line contains three integers xyr, where (xy) is the position of the ACM particle in the 2D picture and r can be 0 or 1, standing for the hydrophilic or hydrophobic type ACM respectively. The absolute value of xy will be no larger than 10000. You may assume that N is no more than 1000. N = 0 signifies the end of the input and need not be processed. Fig.2 shows the positions of ACM particles and the best ICPC position for the last test case in the sample input.

Output 

For each test case, output a line containing a single integer, which is the maximum number of dissolved ACM particles.

Sample Input 

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

Sample Output 

3 
3 
6



题意:给定n个黑色或白色的点,找出一条直线,使得直线一边的白点数加上另一边的黑点数最大


思路:

当n<=3时,答案必定为3,因为不管3个点颜色如何分配都可以将其分为最大值为3

当n>3时,必定有一个直线可以通过两个点,因此我们可以枚举2点组成一条直线再分别统计两边的最大值,这样复杂度为O(n^3),必定超时

于是我们先枚举一个点,然后以该点为原点,求出其他点的极角,对极角排序后进行旋转,旋转的过程中每扫过一个点就可以动态维护一次最大值,这样枚举的复杂度为O(n),排序复杂度为O(nlogn),因此,总复杂度为O(n^2 * logn)

采用极角排序+扫描的方式还需要几个细节问题需要我们去解决

1.如何计算极角

在这里我们需要采用cmath里面的库函数atan2(double y,double x)

atan2(y,x)所表达的意思是以坐标原点为起点,指向(x,y)的射线在坐标平面上与x轴正方向之间的角的角度。也就是当我们枚举到点i时,我们计算出其他点以i为原点后的相对坐标后,带入atan2函数即可求得极角,然后对结构体进行排序即可完成极角排序工作

2.如何快速动态维护最大值

这里我们可以使用一个小技巧,将每一个黑点,都相对当前的枚举点进行中心对称操作,即把相对坐标取反,这样原本在线坐标的黑点就会出现在右边,在右边的黑点就会出现在左边,这样我们只需要统计直线一侧的所有点即可

3.直线如何旋转扫描

我们将原点和极角排序后最小的点作为初始直线,然后将该直线旋转180°,统计那一侧点的数量,也就是说我们需要两个变量L和R,每次从低到高枚举L,即枚举直线,然后枚举R进行统计一侧的点,直到R和L点构成的直线超过180°,对180°的判断我们采用叉积的形式,

至此我们的问题基本解决了,代码如下

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>

using namespace std;


const int maxn=1000+50;
typedef struct
{
    int x,y,c;
    double rad;
}Point;

Point P[maxn],T[maxn];

bool lessthanPIE(int l,int r)
{
    return T[l].x*T[r].y>=T[r].x*T[l].y;
}

bool cmp(const Point & p1,const Point &p2)
{
    return p1.rad<p2.rad;
}
int main()
{
    int n,i,j;
    int l,r,sum,ans;
    while(~scanf("%d",&n) && n)
    {
        for(i=0;i<n;i++)
            scanf("%d%d%d",&P[i].x,&P[i].y,&P[i].c);

        ans=0;
        if(n<=3)
        {
            printf("%d\n",n);
            continue;
        }
        for(i=0;i<n;i++)
        {
            int k=0;
            for(j=0;j<n;j++)
            {
                if(i!=j)
                {
                    T[k].x=P[j].x-P[i].x;
                    T[k].y=P[j].y-P[i].y;

                    if(P[j].c)
                    {
                        T[k].x=-T[k].x;
                        T[k].y=-T[k].y;
                    }

                    T[k].rad=atan2(T[k].y,T[k].x);
                    k++;
                }

            }

            sort(T,T+k,cmp);



            sum=1;
            for(l=0,r=0;l<k;)
            {
                if(l==r)
                {
                    r=(r+1)%k;
                    sum++;
                }
                while(l!=r && lessthanPIE(l,r))
                {
                    r=(r+1)%k;
                    sum++;
                }
                ans=max(sum,ans);
                sum--;
                l++;
            }



        }

        printf("%d\n",ans);
    }

    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值