Oriol和David

Oriol 和 David 在一个边长为 16 单位长度的正方形区域内,初始位置分别为(7, 7)和(8, 8)。现在有 20 组、每组包含 20 个位置需要他们访问,位置以坐标(x, y)的形式给出,要求在时间 120 秒内访问尽可能多的点。(x和y均为正整数,且0 ≤ x < 16,0 ≤ y < 16)

注意事项:

  • 针对任意一个位置,Oriol或David中的一人到达即视为访问成功;
  • Oriol和David必须从第 1 组位置开始访问,且必须访问完第 i 组全部20个位置之后,才可以开始第 i + 1 组 20 个位置的访问。同组间各位置的访问顺序可自由决定;
  • Oriol和David在完成当前组位置的访问后,无需返回开始位置、可以立即开始下一组位置的访问;
  • Oriol和David可以向任意方向移动,移动时速率为 2 单位长度/秒;移动过程中,无任何障碍物阻拦。

输入格式:

输入第一行是一个正整数 T (T ≤ 10),表示数据组数。接下来给出 T 组数据。

对于每组数据,输入包含 20 组,每组 1 行,每行由 20 个坐标组成,每个坐标由 2 个整数 x 和 y 组成,代表 Oriol 和 David 要访问的 20 组 20 个位置的坐标;0 ≤ x < 16,0 ≤ y < 16,均用一个空格隔开。

输出格式:

每组数据输出的第一行是一个整数N,代表分配方案访问过的位置组数;

接下来的N组每组的第一行包含两个整数 Ba 和 Bb,分别代表每组分配方案中 Oriol 和 David 负责访问的位置数,第二行和第三行分别包含 Ba 和 Bb 个整数 i,分别代表 Oriol 和 David 负责访问的位置在组内的序号(从0开始计数)。

0 ≤ N ≤ 20,0 ≤ Ba ≤ 20,0 ≤ Bb ≤ 20,0 ≤ i ≤ 19。

输入样例:

1
5 5 3 13 8 7 13 6 6 11 2 0 1 14 9 15 8 9 3 12 4 6 2 10 2 5 4 9 4 1 15 0 11 4 10 0 15 5 10 14
1 0 14 8 0 7 6 8 4 12 12 8 9 8 10 14 9 4 13 4 9 1 2 1 0 2 11 10 7 15 9 6 13 11 3 5 4 5 10 7
7 3 8 13 15 0 5 4 2 8 7 14 4 13 11 1 8 15 4 5 4 7 7 10 6 7 13 4 6 2 9 13 1 12 10 7 10 5 5 11
5 8 12 12 11 5 12 9 2 2 11 15 5 14 0 0 14 0 2 5 7 3 10 1 2 8 4 2 4 8 9 14 1 11 1 9 15 7 3 3
1 9 10 14 7 3 15 5 5 15 3 2 12 11 8 10 3 3 11 5 7 4 6 11 6 1 4 10 11 13 12 4 3 4 1 3 7 5 13 11
3 11 9 8 12 9 14 10 11 13 5 5 4 11 1 12 13 2 10 14 5 15 10 15 11 0 3 6 7 11 4 9 15 0 12 14 10 10 13 11
10 4 9 12 0 13 6 6 7 10 11 15 6 14 1 2 4 9 8 5 4 0 13 11 5 3 13 3 9 8 2 4 13 14 12 12 14 2 8 15
2 8 4 9 13 10 8 5 2 13 12 6 4 4 10 6 14 13 11 5 12 1 6 0 11 2 8 15 12 4 13 8 8 2 9 7 7 13 0 9
0 0 4 0 2 3 10 2 7 3 9 4 2 13 11 11 1 8 11 15 11 2 8 11 10 15 7 9 13 15 15 10 1 2 11 9 14 6 5 5
2 13 6 8 7 14 8 5 15 14 5 6 4 10 14 12 3 14 0 5 4 1 0 14 13 14 12 5 5 9 1 2 2 12 4 8 1 15 7 11
10 5 15 7 6 8 11 10 7 13 14 0 12 2 9 12 4 5 3 8 8 13 7 12 15 15 12 9 15 6 14 3 9 6 15 12 7 9 4 15
0 10 6 2 3 2 6 3 14 6 10 13 3 10 15 9 10 0 7 0 14 15 1 2 13 9 11 11 10 3 6 13 0 14 11 2 9 8 15 5
3 9 13 11 1 1 0 9 5 4 4 9 4 13 10 1 12 11 4 2 0 4 1 7 4 10 4 0 2 1 2 0 13 2 11 10 0 5 15 3
15 11 8 1 12 5 8 5 7 5 7 7 2 4 0 4 7 3 12 6 9 15 5 12 14 11 15 10 8 11 4 10 4 14 13 10 4 4 2 12
9 12 15 13 0 12 0 14 3 1 10 15 15 11 1 12 3 0 5 2 15 10 8 4 9 1 8 0 1 13 2 7 12 13 14 10 6 0 13 15
13 7 14 15 9 4 8 2 7 3 7 11 2 13 5 0 13 5 4 0 12 2 3 2 11 15 9 2 9 7 3 7 4 5 14 5 14 12 9 13
12 11 2 14 2 6 6 12 5 15 13 11 2 0 9 13 7 1 7 11 4 4 2 10 0 8 5 3 6 13 2 7 2 15 6 8 3 5 8 11
12 5 9 9 4 14 3 2 14 2 2 1 9 11 8 10 2 14 12 15 0 13 4 7 0 0 0 6 0 1 4 13 4 3 3 10 15 2 10 10
11 15 8 5 6 15 9 8 2 7 15 14 1 10 14 6 13 6 0 15 4 1 3 12 7 8 12 4 0 10 7 10 0 14 13 5 11 1 15 6
1 12 13 14 6 12 9 0 6 8 3 15 5 4 4 2 15 10 3 6 13 12 8 4 15 3 1 5 7 1 6 14 8 6 2 6 11 3 4 4

输出样例:

2
10 10
1 2 3 4 5 6 7 8 9 0
11 12 13 14 15 16 17 18 19 10
1 19
1
0 2 3 4 5 6 7 8 9 11 12 13 14 15 16 17 18 19 10

注意:样例只代表格式,不具有特别含义。

评分方式:

本题按照你给出的方案的优良程度评定分数。

具体评分规则如下:

  • 本题所有数据点输入均为一样的数据;
  • 评分时,假定输入有 X 组数据,则你的评分答案为你的程序在所有 X 组数据中答案的平均值;
  • 例如,你对 3 组数据,分别访问了 3 个、5 个、8 个点,则你的评分答案为 5.33333...
  • 特别的,如果你输出的答案中有任意一组不合法,则你的评分答案恒定为 0;
  • 输出方案行走超过 120 秒仍然合法,答案计算时只计算 120 秒内的部分;
  • 评测时,从 0 开始的测试点的标准答案依次增大,只有评分答案超过标准答案时,你才可以得到对应测试点的分数。

不合法的情况如下:

  • 输出格式不正确;
  • 重复访问自己已访问的点;(但可以经过)
  • 访问不存在的点。

部分评分标准答案如下:

  • 第 0 号点:20;(即需要访问平均 20 个点才可以获得该点分数)
  • 第 1 号点:70;(同上)
  • 第 2 号点:90;
  • 第 7 号点:150。
  • #include <stdio.h>
    #include <math.h>
    #include <utility>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    #include <stdio.h>
    #include <string.h>
    #include <assert.h>
    FILE *input, *solution, *output;
    
    
    #define N (20)
    #define PB push_back
    #define eps (1e-6)
    typedef vector<int> intArray;
    
    vector<int> va[N+2], vb[N+2];
    
    struct point {
        double x, y;
        point(): x(0), y(0) {}
        point(double x, double y): x(x), y(y) {}
        void set(const point &t) {
            x = t.x, y = t.y;
        }
        void set(double _x, double _y) {
            x = _x, y = _y;
        }
        void read() {
            fscanf(input, "%lf%lf", &x, &y);
        }
    } pt[N+2][N+2], a, b;
    
    inline double sqr(double x) {
        return x*x;
    }
    inline double dis(const point &a, const point &b) {
        return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
    }
    int getClosest(const point &a, const point *pt, const int *f) {
        int res = -1;
        for (int i = 0; i < N; ++i) {
            if (!f[i]) {
                if (res == -1) {
                    res = i;
                }
                else {
                    if (dis(pt[i], a) < dis(pt[res], a)) {
                        res = i;
                    }
                }
            }
        }
        return res;
    }
    
    const point* splitSegment(const point &a, const point &b, double p, double q) {
        return new point((a.x*q+b.x*p)/(p+q), (a.y*q+b.y*p)/(p+q));
    }
    
    double totalTime = 0;
    double endTime = 120;
    
    double getTime(const point &a, const point &b, const point *pt, const intArray &va, const intArray &vb) {
        double ta = va.size() > 0 ? dis(a, pt[va[0]]) : 0, tb = vb.size() > 0 ? dis(b, pt[vb[0]]) : 0;
        for (int i = 1; i < va.size(); ++i) {
            ta += dis(pt[va[i]], pt[va[i-1]]);
        }
        for (int i = 1; i < vb.size(); ++i) {
            tb += dis(pt[vb[i]], pt[vb[i-1]]);
        }
        return max(ta, tb) / 2;
    }
    
    int getRest(const point &a, const point &b, const point *pt, const intArray &va, const intArray &vb) {
        double ta = va.size() > 0 ? dis(a, pt[va[0]]) / 2 : 0, tb = vb.size() > 0 ? dis(b, pt[vb[0]]) / 2 : 0;
        double restTime = endTime - totalTime;
        int ans = (va.size() > 0 && ta < restTime) + (vb.size() > 0 && tb < restTime);
        int ff[30] = {};
        
        for (int i = 1; i < va.size(); ++i) {
            if ((ta += dis(pt[va[i]], pt[va[i-1]]) / 2) < restTime) {
                if (!ff[va[i]]) {
                    ans++;
                    ff[va[i]] = 1;
                }
            } else {
                break;
            }
        }
        for (int i = 1; i < vb.size(); ++i) {
            if ((tb += dis(pt[vb[i]], pt[vb[i-1]]) / 2) < restTime) {
                if (!ff[vb[i]]) {
                    ans++;
                    ff[vb[i]] = 1;
                }
            } else {
                break;
            }
        }
        return ans;
    }
    
    int f[N+2][N+2];
    
    double time = 0;
    
    void work(const point *pt, int f[], intArray &va, intArray &vb) {
        int ta = -1, tb = -1, cnt = 0;
        double disa = 0, disb = 0;
        while (cnt < N) {
            // a arrives at ta -> set next target
            if (ta == -1 || (disa = dis(a, pt[ta])) < eps) {
                disa = dis(pt[ta = getClosest(a, pt, f)], a);
                if (ta != -1 && time + disa / 2 < endTime) {
                    f[ta] = 1;
                    va.PB(ta);
                    cnt++;
                }
            }
            // b arrives at tb -> set next target
            if (tb == - 1 || (disb = dis(b, pt[tb])) < eps) {
                disb = dis(pt[tb = getClosest(b, pt, f)], b);
                if (tb != -1 && time + disb / 2 < endTime) {
                    f[tb] = 2;
                    vb.PB(tb);
                    cnt++;
                }
            }
            // move
            if (disa < disb) {
                a.set(pt[ta]);
                b.set(*splitSegment(b, pt[tb], disa, disb-disa));
                time += disa / 2;
                // printf("a move to %f %f, b move to %f %f, time %f\n", a.x, a.y, b.x, b.y, time);
            }
            else {
                b.set(pt[tb]);
                a.set(*splitSegment(a, pt[ta], disb, disa-disb));
                time += disb / 2;
                // printf("a move to %f %f, b move to %f %f, time %f\n", a.x, a.y, b.x, b.y, time);
            }
        }
        
        a.set(pt[va[va.size() - 1]]);
        b.set(pt[vb[vb.size() - 1]]);
    }
    
    void print() {
        int n = 0;
        for (; n < N; ++n) {
            int ok = 0;
            for (int j = 0; j < N; ++j) {
                ok |= f[n][j];
            }
            if (!ok) {
                break;
            }
        }
        printf("%d\n", n);
        for (int i = 0; i < n; ++i) {
            printf("%d %d\n", va[i].size(), vb[i].size());
            for (int j = 0; j < va[i].size(); ++j) {
                printf("%d%c", va[i][j], " \n"[j == va[i].size() - 1]);
            }
            for (int j = 0; j < vb[i].size(); ++j) {
                printf("%d%c", vb[i][j], " \n"[j == vb[i].size() - 1]);
            }
        }
    }
    
    void my_assert(bool x, const char* err) {
        if (!x) {
            fprintf(stderr, "%s\n", err);
            exit(1);
        }
    }
    
    int main(int argc, char** argv) {
        input = fopen("input", "r");
        output = fopen("output", "r");
        solution = fopen("user_output", "r");
        int valve = 300;
        fscanf(output, "%d", &valve);
        my_assert(valve >= 0 && valve <= 300, "valve should be in [0, 300]");
        if (input && solution) {
            int number;
            fscanf(input, "%d", &number);
            my_assert(number >= 0 && number <= 10, "case number should be in [0, 10]");
            int res = 0;
            for (int _ = 0; _ < number; ++_) {
                for (int i = 0; i < N; ++i) {
                    for (int j = 0; j < N; ++j) {
                        pt[i][j].read();
                        f[i][j] = 0;
                        va[i].clear();
                        vb[i].clear();
                    }
                }
                
                int n = 0;
                fscanf(solution, "%d", &n);
                my_assert(0 <= n && n <= N, "n should be in [0, 20]");
                for (int i = 0, sa, sb; i < n; ++i) {
                    fscanf(solution, "%d%d", &sa, &sb);
                    my_assert((sa >= 0 && sa <= N && sb >= 0 && sb <= N), "sa and sb should be in [0, 20]");
                    int f[N+4] = {};
                    for (int j = 0, x; j < sa; ++j) {
                        fscanf(solution, "%d", &x);
                        my_assert((x >= 0 && x < N && (f[x] & 1) == 0), "a index range error or duplicate");
                        va[i].PB(x);
                        f[x] |= 1; 
                    }
                    for (int j = 0, x; j < sb; ++j) {
                        fscanf(solution, "%d", &x);
                        // assert(f[x] == 0);
                        my_assert((x >= 0 && x < N && (f[x] & 2) == 0), "b index range error or duplicate");
                        vb[i].PB(x);
                        f[x] |= 2;
                    }
                }
                totalTime = 0;
                a.set(7.0,7.0);
                b.set(8.0,8.0);
                for (int i = 0; i < n; ++i) {
                    totalTime += getTime(a, b, pt[i], va[i], vb[i]);
                    int tot = 0;
                    int ff[30] = {};
                    for (auto ia: va[i]) {
                        ff[ia] = 1;
                    }
                    for (auto ib: vb[i]) {
                        ff[ib] = 1;
                    }
                    for (int j = 0; j < 20; ++j) {
                        tot += ff[j];
                    }
                    if (totalTime > endTime || tot < 20) {
                        totalTime -= getTime(a, b, pt[i], va[i], vb[i]);
                        tot = getRest(a, b, pt[i], va[i], vb[i]);
                        printf("%d\n", tot);
                        res += i*20 + tot;
                        break;
                    }
                    if (va[i].size() > 0) a.set(pt[i][va[i][va[i].size() - 1]]);
                    if (vb[i].size() > 0) b.set(pt[i][vb[i][vb[i].size() - 1]]);
                }
                printf("Total time: %f\n", totalTime);
            }
            printf("Score: %f\n", res / (double) number);
            return res < valve * number;
        }
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

暴躁的梁小忠

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

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

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

打赏作者

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

抵扣说明:

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

余额充值