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;
      }
  }
相关推荐
_GR14 分钟前
每日OJ题_牛客_牛牛冲钻五_模拟_C++_Java
java·数据结构·c++·算法·动态规划
凯子坚持 c16 分钟前
C语言复习概要(三)
c语言·开发语言
ROBIN__dyc26 分钟前
表达式
算法
无限大.27 分钟前
c语言200例 067
java·c语言·开发语言
无限大.30 分钟前
c语言实例
c语言·数据结构·算法
Death20033 分钟前
Qt 中的 QListWidget、QTreeWidget 和 QTableWidget:简化的数据展示控件
c语言·开发语言·c++·qt·c#
六点半88834 分钟前
【C++】速通涉及 “vector” 的经典OJ编程题
开发语言·c++·算法·青少年编程·推荐算法
@haihi43 分钟前
冒泡排序,插入排序,快速排序,选择排序
数据结构·算法·排序算法
quaer1 小时前
Open-Sora全面开源?
开发语言·算法·机器学习·matlab·矩阵
Hello.Reader1 小时前
TopK算法在大数据重复数据分析中的应用与挑战
大数据·算法·数据分析