CSU 2029 ATRC 2017

2029: Border Wall

Submit Page      Summary      Time Limit: 3 Sec       Memory Limit: 512 Mb       Submitted: 2       Solved: 1    

Description

Through one of the most controversial presidential elections in the world, Mr. Trunk was finally elected as the president of Demoland. During his long presidential campaign, Mr. Trunk made a series of strange promises, one of which was to build a wall along the border of Demoland with its neighboring country, Indoland. Now, months after his election, Mr. Trunk has started thinking on how to really build the wall. To keep things simple, he has decided to build the wall along a straight line. However, there are still several difficulties. The main issue is that the houses owned by the citizens of these two neighboring countries are so mixed that it is almost impossible to separate them by a straight wall. Wherever the wall is built, some houses must be evacuated and their residents must be moved to the other side of the wall in order to keep all citizens of each county on one side of the wall. The second issue is that the wall itself has some width, meaning that all houses intersected by the wall must be destructed. Of course, evacuating or destructing each house has a cost, and if the total number of such houses is high, it would raise a vigorous public protest. To make his final decision, Mr. Trunk is looking for a keen advisor to tell him how many houses must be evacuated/destructed at the minimum in order to build a straight border wall of a desired width. Being active in ACM ICPC, you have been selected as an advisor to Mr. President. The locations of the houses owned by the citizens of each country is given to you as a set of points in the plane. The desired width of the border wall is also given to you by the president. Your task is to compute the minimum number of points (houses) that must be removed (destructed or evacuated) so that the remaining point sets can be separated by a wall of the given width. Two point sets are called separated by a wall if (i) no two points from different sets lie in the same side of the wall, and (ii) none of the points intersects the wall except on its boundary lines.

Input

There are multiple test cases in the input. The first line of each test case contains three positive integers n, k, d, where n and k indicate the number of houses owned by the citizens of Demoland and Indoland, respectively, and d indicates the width of the border wall (1 ⩽ n, k ⩽ 100, and 0 ⩽ d < 1, 000). The next n lines, each contains two integers x and y (0 ⩽ x, y ⩽ 10, 000), where (x, y) represents the location of a house owned by a citizen of Demoland. Analogously, the next k lines represent the location of the houses owned by the citizens of Indoland. Note that no two houses are located in the same position. The input terminates with a line containing “0 0 0” which should not be processed.

Output

For each test case, output a line containing the minimum number of the points that must be removed to construct the wall. Note that all houses from a country may be destructed/evacuated in the optimal solution.

Sample Input

2 2 1
1 0
3 0
2 7 
4 0 
2 2 1 
1 1 
3 0 
2 2 
4 1 
0 0 0

Sample Output

1
0

Hint

Source

ATRC2017


题目大意:二维坐标系中,有n个点属于A类,k个点属于B类,现在可以删除一些点,使得一堵宽为d的墙可以将两类点分开(墙的一边只有一种点),问最少删几个点。


题解:首先,将墙抽象成距离为d的平行线,若直线没有经过点存在正解,那么经过点也一定存在正解。所以我们不妨认为直线一定经过点。

正常点的图,直线一定会经过2个点,我们只需要暴力枚举每条直线,看看当先情况下要满足要求需要删几个点。枚举时分两种情况,因为直线的两侧距离为d的直线都可以。那又如何求解呢?

设枚举时两条直线为l1,l2,再枚举所有点,将他们分类。首先,夹在平行线间的点是一定要删除的。若点在平行线外侧,我们统计靠近l1、l2的两类点分别有多少个(4个数据)。然后我们再决定是选择l1侧为A类、l2侧为B类还是l1侧为B类、l2侧为A类,两种情况分别会删去一些点,再加上夹在平行线间的点的个数,就是当前平行线下满足要求需要删除的点的个数。取最小值即可。

对于不正常的图,就有点坑了,数据中有所有点都共线的情况,就需要特殊处理。

当d==0时,为了方便,将d设为0.0001。


代码:

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#define LL long long
#define N 110
#define MOD 1000000007
#define pi 3.141592653589793
using namespace std;
const double eps=1e-6;
int dcmp(double x){if (fabs(x)<eps)return 0;else return x<0?-1:1;}

struct Point
{
    double x,y;
    bool operator < (const Point &a)const
    {return dcmp(x-a.x)<0 || (dcmp(x-a.x)==0 && dcmp(y-a.y)<0);}
    Point(double x=0,double y=0):x(x),y(y){ }
    void read(){scanf("%lf%lf",&x,&y);}
};
typedef Point Vector;

Vector operator + (Vector a,Vector b){return Vector(a.x+b.x,a.y+b.y);}
Vector operator - (Vector a,Vector b){return Vector(a.x-b.x,a.y-b.y);}
Vector operator * (Vector a,double b){return Vector(a.x*b,a.y*b);}
Vector operator / (Vector a,double b){return Vector(a.x/b,a.y/b);}
bool operator == (Vector a,Vector b){return dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0;}
double Dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;}  //点积
double Length(Vector a){return sqrt(Dot(a,a));}
double Cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;} //叉积
Vector Rotate(Vector a,double rad)// 向量 a 逆时针旋转 rad
{return Vector(a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad));}

//点p到直线ab的距离
double PTL(Point p,Point a,Point b)
{
    Vector v1=b-a,v2=p-a;
    return fabs(Cross(v1,v2)/Length(v1));
}

Point a[N],b[N],c[N<<1],v,p;
int n,m,ans;
double d,aa;

int check(Point x,Point y,Vector v)
{
    double p1,p2; int p[2]={0},pp[2]={0},t=0;
    for (int i=1;i<=n;i++)
    {
        p1=PTL(a[i],x,x+v);p2=PTL(a[i],y,y+v);
        int k=0;
        if (dcmp(p1)==0 || dcmp(p2)==0) k=1;
        if (dcmp(p1+p2-d)==0 && !k) t++;else
        if (dcmp(p1-p2)<0)p[0]++;else pp[0]++;
    }
    for (int i=1;i<=m;i++)
    {
        p1=PTL(b[i],x,x+v);p2=PTL(b[i],y,y+v);
        int k=0;
        if (dcmp(p1)==0 || dcmp(p2)==0) k=1;
        if (dcmp(p1+p2-d)==0 && !k) t++;else
        if (dcmp(p1-p2)<0)p[1]++;else pp[1]++;
    }
    t+=min(p[1]+pp[0],p[0]+pp[1]);
    return t;
}

int main()
{
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);
    while (~scanf("%d%d%lf",&n,&m,&d) && n)
    {
        ans=100000; if(d==0)d=0.0001;
        for (int i=1;i<=n;i++) a[i].read(),c[i]=a[i];
        for (int i=1;i<=m;i++) b[i].read(),c[i+n]=b[i];
        int line=0;
        for (int i=2;i<=n+m;i++) if (dcmp(Cross(c[2]-c[1],c[i]-c[1]))==0) line++;
        if (line==n+m-1) line=1;else line=0;
        for (int i=1;i<=n+m;i++) for(int j=i+1;j<=n+m;j++)
        {
            v=c[j]-c[i];
            if (line) v=Rotate(v,pi*0.5);
            if (dcmp(v.y)<0 || dcmp(v.y==0) && dcmp(v.x)<0) v=v*(-1);
            Point t=Rotate(v,pi*0.5);
            t=t*d/Length(t);
            ans=min(ans,check(c[i],c[i]+t,v));
            ans=min(ans,check(c[i],c[i]-t,v));
        }
        printf("%d\n",ans);
    }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值