// Verificador de "La gira más corta": verificador ENTRADA ESPERADA SALIDA.
// En ESPERADA está solo el largo mínimo. Comprueba que salga ese largo, que el recorrido pase una
// vez por cada ciudad y que su largo, medido aquí con la fórmula del enunciado, sea el que se escribió.
// Termina con 0 si todo está bien, y con 1 y un mensaje si no.
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <numbers>
#include <string>
#include <vector>

namespace {

struct Place {
    double latitude;
    double longitude;
};

[[noreturn]] void reject(const std::string& reason) {
    std::cout << reason << '\n';
    std::exit(1);
}

// Convierte una palabra en número sin riesgo de overflow: solo dígitos, y a lo sumo 18.
bool parse_number(const std::string& word, long long& value) {
    if (word.empty() || word.size() > 18) return false;
    value = 0;
    for (char c : word) {
        if (c < '0' || c > '9') return false;
        value = value * 10 + (c - '0');
    }
    return true;
}

long long distance_m(const Place& a, const Place& b) {
    const double to_radians = std::numbers::pi / 180.0;
    const double phi1 = a.latitude * to_radians;
    const double phi2 = b.latitude * to_radians;
    const double half_dphi = (phi2 - phi1) / 2.0;
    const double half_dlambda = (b.longitude - a.longitude) * to_radians / 2.0;
    const double h = std::sin(half_dphi) * std::sin(half_dphi) +
                     std::cos(phi1) * std::cos(phi2) * std::sin(half_dlambda) * std::sin(half_dlambda);
    return static_cast<long long>(std::ceil(2.0 * 6371000.0 * std::asin(std::sqrt(std::min(1.0, h)))));
}

}  // namespace

int main(int argc, char* argv[]) {
    if (argc != 4) reject("uso: verificador ENTRADA ESPERADA SALIDA");
    std::ifstream input(argv[1]);
    std::ifstream expected(argv[2]);
    std::ifstream output(argv[3]);

    std::size_t n = 0;
    input >> n;
    std::vector<Place> places(n);
    for (auto& place : places) {
        std::string name;
        input >> place.latitude >> place.longitude;
        std::getline(input, name);
    }
    long long minimum = 0;
    expected >> minimum;

    std::string word;
    long long length = 0;
    if (!(output >> word) || !parse_number(word, length)) reject("la primera palabra no es un largo válido");
    if (length != minimum) reject("largo mínimo esperado: " + std::to_string(minimum) + ", salió " + word);

    std::vector<std::size_t> tour;
    std::vector<char> seen(n, 0);
    for (std::size_t k = 0; k < n; k++) {
        long long city = 0;
        if (!(output >> word)) reject("faltan ciudades en el recorrido");
        if (!parse_number(word, city)) reject("número de ciudad inválido: " + word);
        if (city < 0 || city >= static_cast<long long>(n)) reject("ciudad fuera de rango: " + word);
        const std::size_t v = static_cast<std::size_t>(city);
        if (seen[v] != 0) reject("la ciudad " + word + " aparece dos veces");
        seen[v] = 1;
        tour.push_back(v);
    }
    if (output >> word) reject("sobra texto después del recorrido: " + word);

    long long measured = 0;
    for (std::size_t k = 0; k < n; k++) measured += distance_m(places[tour[k]], places[tour[(k + 1) % n]]);
    if (measured != length) reject("el recorrido mide " + std::to_string(measured) + ", no " + std::to_string(length));
    return 0;
}
