hdu 5928 极角排序+dp



链接:戳这里


Birthday Gift
Time Limit: 9000/4500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Problem Description

Both Mr. Frog and Wallice love running. Wallice missed Mr. Frog’s birthday recently,so he decided to give a belated birthday gift. He quickly found out an idea: he decided to run a closed curve to contain those meaningful buildings. Unfortunately, he only gets a little time left since he is going to attend an important press conference.

Wallice wants to know the maximal number of buildings can be contained in the closed curve. Note that his speed is 1.

Input

The first line contains only one integer T,which indicates the number of test cases.

For each test case, the first line contains an integer N (1≤N≤80), and a double t (0≤l≤5000) indicating the numbers of buildings Wallice cares about and the time he has.

In the following n lines, the i-th line contains two doubles xi,yi(−600≤xi,yi≤600) indicating the position of the buildings.

Output

For each test case,output one line “Case #x: ans’’,where x is the case number (starting from 1) following with ans indicating the maximum number of buildings Wallice can circled in in limited time.

Sample Input

2
4 4.1
0 0
0 1
1 0
1 1
4 3.5
0 0
0 1
1 0
1 1

Sample Output

Case #1: 4
Case #2: 3
Hint

For the second sample, Wallice does not have enough time to circle all the four buildings so he circles three of them instead.

It is guaranteed that the answer would not change even if l changes up to 10^-5, and there would not be any 3 points on one line even if any point changes its position up to 10^-5.



题意:
平面上给出n(80)个点,以及长度为L的绳子
现在要求用绳子去围点,问做多能围住多少个点


思路:

枚举当前的点st作为最下方的点,现在从st出发逆时针去绕点,最多能绕多少个点?

以st为向量的起点去极角排序

dp[i][j]表示:i点作为st能围到的逆时针上最远的点,从st-i这些点里面围j个点的最少绳子长度

然后以当前的dp[i][]去更新满足条件的dp[i+1][]

至于判断一个点是否被包围,只需要满足当前判断的点在围住的绳子左边就可以了


代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
const double eps=-1e-8;
struct point{
    double x,y;
    point(double x=0,double y=0):x(x),y(y){}
    point operator - (const point &a)const{
        return point(x-a.x,y-a.y);
    }
    double operator * (const point &a)const{
        return x*a.y-y*a.x;
    }
    double operator ^ (const point &a)const{
        return x*a.x+y*a.y;
    }
    bool operator < (const point &t)const{ /// 极角排序
        bool up[2]={0,0};
        if(y>0 || (y==0 && x>0)) up[0]=1;
        if(t.y>0 || (t.y==0 && t.x>0)) up[1]=1;
        if(up[0]^up[1]) return up[0];
        return (*this)*t ? (*this)*t>0 : ((*this)^(*this))<(t^t);
    }
}s[110],V[110];
int n;
double L;
double dp[110][110];
double disn(point a){
    return sqrt(a.x*a.x+a.y*a.y);
}
int main(){
    int T;
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++){
        scanf("%d%lf",&n,&L);
        for(int i=1;i<=n;i++) scanf("%lf%lf",&s[i].x,&s[i].y);
        int ans=0;
        for(int i=1;i<=n;i++){
            int m=0;
            for(int j=1;j<=n;j++){
                if(i==j) continue;
                if(s[j].y-s[i].y>=eps) V[++m]=s[j]-s[i];
            }
            sort(V+1,V+m+1);
            memset(dp,127,sizeof(dp));
            for(int j=1;j<=m;j++){
                double dis=disn(V[j]);
                if(L-dis<eps) continue;
                dp[j][1]=dis;
                for(int k=j+1;k<=m;k++){
                    double link=disn(V[k]-V[j]);
                    if(L-dis-link<eps) continue;
                    int cnt=1;
                    for(int l=j+1;l<k;l++){
                        if((V[k]-V[j])*(V[l]-V[j])>0) cnt++;
                    }
                    for(int l=1;l<=j && l+cnt<=k;l++){
                        if(L-dp[j][l]-link<eps) continue;
                        dp[k][l+cnt]=min(dp[k][l+cnt],dp[j][l]+link);
                    }
                }
                for(int l=1;l<=m;l++) {
                    if(L-dp[j][l]-dis>eps) ans=max(ans,l);
                }
            }
        }
        printf("Case #%d: %d\n",cas,ans+1);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值