水果忍者

目描述
    你知道水果忍者 是一个智能手机上面很流行的游
    个出色的游 迎合了人类最喜 的运 动轨 迹:抛物 线 。就是各种各 物体被扔出去之后都会形成的曲 线 里的 问题 也是关于抛物 线 的。
    在有 N 个水果,假 就是一个个在平面上的的 ,有着同 的半径。每个水果有着各自的位置和移 速度。由于重力的影响( 里假 重力常数 g=10) ,所有水果都从一开始就沿着抛物 线 。你的目 就是在 定的 时间 限制之内,一次切到最多的水果,即是找到在某一 刻的一条直 线 穿 最多的
入格式
入包含多 给测试 数据。
入的第一行 出了 测试 数据个数 T
每个 测试 数据首先 出三个整数,水果数目 N(<=100) ,水果的半径R(<=1000), 时间 限制 E(<=1000)
接下来有N行,每行 4 数,分别 对应圆 心坐 (xi,yi) 和速度(vxi,vyi)。
所有数都是 采用标 位,所以你可以放心使用以下著名的物理公式来 算某一 刻水果所 的位置:
x' = x + vx * t
y' = y + vy * t - 0.5 * 10 * t * t
数据保 所有 的浮点数的 绝对值 小于 100000
出格式
对应 每个 测试 数据, 出一个整数,即在 限内可以同 切到的水果数目的最大
2
4 1 2
2.0 4.0 1.0 0.0
5.0 4.0 2.0 0.0
2.0 12.0 1.5 -4.0
-2.0 -5.0 10.0 10.0
4 1 1
2.0 4.0 1.0 0.0
5.0 4.0 2.0 0.0
2.0 12.0 1.5 -4.0
-2.0 -5.0 10.0 10.0
4
3
提示
注意一条直 线 穿 一个 意味 着, 心与直 线 的距离小于 的半径加上精度 (1e-5)



#include <cstdio>
#include <cstring>
#include <cmath>
#include <cassert>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 101;
const double INF = 1e8;
const double EPS = 1e-5;
const double MAXLOOP = 100;
struct seg {
    seg() { l = 1; r = 0; }
    seg(double il, double ir) { l = il; r = ir; }
    bool empty() { return r < l - EPS; }
    double l, r;
};
struct point {
    int mrk;
    double pos;
}points[maxn * 2];
struct vect {
   
    double d[20];
    int n;
    int size() {
        return n;
    }
    vect() {
        n= 0;
    }
    void push_back(double x) {
        d[n++] = x;
    }
    double operator [] (int index) {
        return d[index];
    }
};
int pn;
double x[maxn], y[maxn], vx[maxn],vy[maxn];
int n, r, e; // number, radius, time limit
int best; // maximum number of cutting
void add_seg(seg &s) {
    if (abs(s.l - s.r)<EPS) s.r = s.l;
    points[pn].mrk = 1;
    points[pn].pos = s.l;
    ++pn;
    points[pn].mrk = 0;
    points[pn].pos = s.r;
    ++pn;
}
vectdifferentiate(vect co) {
    vect res;
    for (int i = 1; i < co.size(); ++i) {
        res.push_back(co * i);
    }
    return res;
}
double substitute(vect co, double x) {
    double res = 0, tmp = 1;
    for (int i = 0; i < co.size(); ++i) {
        res += tmp * co;
        tmp *= x;
    }
    return res;
}
vectremove_dup(vect vec) {
    vect res;
    if (vec.size() == 0) return res;
    //sort(vec.begin(), vec.end());
    sort(vec.d, vec.d+vec.n);
    res.push_back(vec[0]);
    for (int i=1;i<vec.size();++i) {
        if (vec - vec[i-1] > EPS * 10)res.push_back(vec);
    }
    return res;
}
bool newton(vect co, vect dco, double x, double &res_x) {
    double last = -INF;
    int count = 0;
    while (count++ < MAXLOOP) {
        double f = substitute(co, x);
        double fp = substitute(dco, x);
        if ( abs(fp) < EPS ) {
            // no idea whether this works
            x += EPS;
            continue;
        }
        x -= f / fp;
        if ( abs(x - last) < EPS ) {
            res_x = x;
            return true;
        }
        last = x;
    }
    return false;
}
vectsolveeqs(vect co) {
    vect root;
   
    if (co.size() <= 2) {
        if (co.size() == 2 && co[1] != 0) {
            root.push_back(-co[0] / co[1]);
        }
        return root;
    }
    vect dco = differentiate(co); // differentail coefficient
    vect droot = solveeqs(dco);
    droot.push_back(-INF);
    droot.push_back(INF);
    sort(droot.d, droot.d+droot.n);
    //sort(droot.begin(), droot.end());
   
    for (int i=1;i<droot.size(); ++i) {
        double initx = (droot[i-1] + droot)* 0.5, res;
        if (newton(co, dco, initx, res)) {
            root.push_back(res);
        }
    }
    return remove_dup(root);
}
//sigma(ax^n) <= 0
vector<seg> solvele(vect co) {
    vect root = solveeqs(co);
    vector<seg> res;
    bool neg = substitute(co, -INF) < 0 ;
    double last = -INF;
    for (int i=0;i<root.size();++i) {
        if (neg) {
            res.push_back(seg(last, root));
        }
        last = root;
        neg ^=1;
    }
    if (neg) res.push_back(seg(last, INF));
    return res;
}
vectnegpoly(vect co) {
    for (int i = 0; i < co.size(); ++i) {
        //co *= -1;
        co.d *= -1;
    }
    return co;
}
vector<seg> solvege(vect co) {
    return solvele(negpoly(co));
}
vectmultipoly(vect co1, vect co2) {
    vect res;
    for (int i = 0; i<co1.size()+co2.size()-1;++i) res.push_back(0);
    for (int i = 0; i < co1.size(); ++i) {
        for (int j = 0; j < co2.size(); ++j) {
            //res[i+j] += co1 * co2[j];
            res.d[i+j] += co1 * co2[j];
        }
    }
    return res;
}
vectsumpoly(vect co1, vect co2) {
    vect res;
    for (int i = 0; i < co1.size() || i < co2.size(); ++i) {
        double ta, tb;
        if (i < co1.size()) ta = co1; else ta = 0;
        if (i < co2.size()) tb = co2; else tb = 0;
        res.push_back(ta + tb);
    }
    return res;
}
// ax +b
vect lco(double a, double b) {
    vect res;
    res.push_back(b);
    res.push_back(a);
    return res;
}
segintersect(seg a, seg b) {
    seg res;
    if (a.l > b.l) res.l = a.l; else res.l = b.l;
    if (a.r < b.r) res.r = a.r; else res.r = b.r;
    return res;
}
void fix_time_limit(seg &ret) {
    if (ret.l < 0) ret.l = 0;
    if (ret.r > e) ret.r = e;
}
void calc_valid_seg( int a, int b, int c) {
    double x1 = x[b] - x[a], x2 = x[c] - x[a];
    double y1 = y[b] - y[a], y2 = y[c] - y[a];
    double vx1 = vx[b] - vx[a], vx2 = vx[c] - vx[a];
    double vy1 = vy[b] - vy[a], vy2 = vy[c] - vy[a];
    vect tmp;   
    vect co = sumpoly(multipoly(lco(vy1, y1), lco(vx2, x2)),negpoly(multipoly(lco(vy2, y2), lco(vx1, x1))));
    //  int start2 =clock();
    vector<seg> seg1 = solvege(co);
    tmp.push_back(-4*r*r);
    vect co2 = sumpoly(multipoly(co, co),multipoly(sumpoly(multipoly(lco(vx1,x1), lco(vx1,x1)), multipoly(lco(vx1,x1),lco(vx1,x1))), tmp));
    vector<seg> seg2 = solvele(co2);
    for (int i = 0; i < seg1.size(); ++i) {
        fix_time_limit(seg1);
        if (seg1.empty()) continue;
        for (int j = 0; j < seg2.size(); ++j){
            fix_time_limit(seg2[j]);
            if (seg2[j].empty()) continue;
            seg tmpseg = intersect(seg1,seg2[j]);
            if (!tmpseg.empty())add_seg(tmpseg);
        }
    }
}
int cmp(const point & l, const point & r) {
    if (l.pos != r.pos) return l.pos < r.pos;
    return l.mrk < r.mrk;
}
void sort_seg() {
    sort(points, points + pn, cmp);
}
void calc_max() {
    int i, tot = 0, maxx = 0;
    for (i = 0; i < pn; ++i) {
        if (points.mrk) ++tot; else --tot;
        if (tot > maxx) maxx = tot;
    }
    if (maxx + 2 > best) best = maxx + 2;
}
int main() {
    //freopen("D:\\Contest\\4+2\\2011\\ninjapro\\input1.txt","r", stdin);
    int t, i, j, k;
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d%d", &n, &r, &e);
        for (i=0;i<n;++i) {
            scanf("%lf%lf%lf%lf", &x, &y,&vx, &vy);
        }
        best = 2;
        // enumerate the fixed line
        for (i=0;i<n;++i) {
            for (j=0;j<n;++j) {
                pn = 0;
                if (i == j) continue;
                for (k = 0; k < n; ++k) {
                    if (i == k || j == k) continue;
                    calc_valid_seg(i, j, k);
                }
                sort_seg();
                calc_max();
                //printf("%d %d\n", i,j);
            }
        }
        printf("%d\n", best);
    }
    return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值