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;
}
}