#include #include #include // BEGIN expanded instance.hpp #include #include #include #include using i64 = std::int64_t; struct Game { int n = 0, m = 0; std::vector> a; }; inline Game generate_game(int n, int m, i64 coefficient_limit, std::uint64_t seed) { std::mt19937_64 rng(seed); std::uniform_int_distribution value(-coefficient_limit, coefficient_limit); Game g; g.n = n; g.m = m; g.a.assign(n, std::vector(m)); for (auto& row : g.a) for (i64& x : row) x = value(rng); return g; } inline void print_game(const Game& g, std::ostream& out = std::cout) { out << g.n << ' ' << g.m << '\n'; for (int i = 0; i < g.n; ++i) for (int j = 0; j < g.m; ++j) out << g.a[i][j] << (j + 1 == g.m ? '\n' : ' '); } inline bool read_game(Game& g, std::istream& in = std::cin) { if (!(in >> g.n >> g.m)) return false; g.a.assign(g.n, std::vector(g.m)); for (auto& row : g.a) for (i64& x : row) in >> x; return true; } // END expanded instance.hpp // BEGIN expanded lp.hpp #include #include #include #include #include #include template struct TableauSimplex { // A practical absolute tolerance avoids pivoting on round-off noise after // a degenerate optimum has effectively been reached. static constexpr Real EPS = std::is_same_v ? 1e-12L : 1e-9; int m, n; std::vector basis, nonbasis; std::vector> d; long long pivots = 0; long long pivot_limit; TableauSimplex(const std::vector>& a, const std::vector& b, const std::vector& c, long long limit = 10000000) : m((int)b.size()), n((int)c.size()), basis(m), nonbasis(n + 1), d(m + 2, std::vector(n + 2)), pivot_limit(limit) { for (int i = 0; i < m; ++i) for (int j = 0; j < n; ++j) d[i][j] = a[i][j]; for (int i = 0; i < m; ++i) basis[i] = n + i, d[i][n] = -1, d[i][n + 1] = b[i]; for (int j = 0; j < n; ++j) nonbasis[j] = j, d[m][j] = -c[j]; nonbasis[n] = -1; d[m + 1][n] = 1; } void pivot(int r, int s) { if (++pivots > pivot_limit) throw std::runtime_error("simplex pivot limit exceeded"); const Real inv = 1 / d[r][s]; for (int i = 0; i < m + 2; ++i) if (i != r) for (int j = 0; j < n + 2; ++j) if (j != s) d[i][j] -= d[r][j] * d[i][s] * inv; for (int j = 0; j < n + 2; ++j) if (j != s) d[r][j] *= inv; for (int i = 0; i < m + 2; ++i) if (i != r) d[i][s] *= -inv; d[r][s] = inv; std::swap(basis[r], nonbasis[s]); } bool simplex(int phase) { const int objective = phase == 1 ? m + 1 : m; while (true) { int s = -1; const bool bland = pivots >= 10000; for (int j = 0; j <= n; ++j) { if (phase == 2 && nonbasis[j] == -1) continue; if (d[objective][j] >= -EPS) continue; if (s == -1 || (bland ? nonbasis[j] < nonbasis[s] : d[objective][j] < d[objective][s] - EPS) || (!bland && std::abs(d[objective][j] - d[objective][s]) <= EPS && nonbasis[j] < nonbasis[s])) s = j; } if (s == -1) return true; int r = -1; for (int i = 0; i < m; ++i) if (d[i][s] > EPS) { if (r == -1 || d[i][n + 1] / d[i][s] < d[r][n + 1] / d[r][s] - EPS || (std::abs(d[i][n + 1] / d[i][s] - d[r][n + 1] / d[r][s]) <= EPS && basis[i] < basis[r])) r = i; } if (r == -1) return false; pivot(r, s); } } // Returns -infinity if infeasible and +infinity if unbounded. Real solve(std::vector& x) { int r = 0; for (int i = 1; i < m; ++i) if (d[i][n + 1] < d[r][n + 1]) r = i; if (d[r][n + 1] < -EPS) { pivot(r, n); if (!simplex(1) || d[m + 1][n + 1] < -EPS) return -std::numeric_limits::infinity(); if (std::abs(d[m + 1][n + 1]) > EPS) return -std::numeric_limits::infinity(); for (int i = 0; i < m; ++i) if (basis[i] == -1) { int s = 0; for (int j = 1; j <= n; ++j) if (std::abs(d[i][j]) > std::abs(d[i][s])) s = j; pivot(i, s); } } if (!simplex(2)) return std::numeric_limits::infinity(); x.assign(n, 0); for (int i = 0; i < m; ++i) if (basis[i] < n) x[basis[i]] = d[i][n + 1]; return d[m][n + 1]; } }; template struct LinearProgram { std::vector> a; std::vector b, c; }; // END expanded lp.hpp // BEGIN expanded game_lp.hpp #include #include #include #include inline i64 minimum_entry(const Game& g) { i64 result = g.a[0][0]; for (const auto& row : g.a) for (i64 x : row) result = std::min(result, x); return result; } inline i64 shift_amount(const Game& g) { return 1 + std::max(0, -minimum_entry(g)); } template LinearProgram make_shifted_reciprocal_lp(const Game& g, i64 shift) { LinearProgram lp; lp.a.assign(g.n, std::vector(g.m)); lp.b.assign(g.n, Real(1)); lp.c.assign(g.m, Real(1)); for (int i = 0; i < g.n; ++i) for (int j = 0; j < g.m; ++j) lp.a[i][j] = Real(g.a[i][j] + shift); return lp; } // Eliminate p_(N-1)=1-sum_{i LinearProgram make_direct_game_lp(const Game& g, bool normalize_rows) { const i64 low = minimum_entry(g); LinearProgram lp; lp.a.assign(g.m + 1, std::vector(g.n)); lp.b.assign(g.m + 1, 0); lp.c.assign(g.n, 0); lp.c[g.n - 1] = 1; for (int j = 0; j < g.m; ++j) { for (int i = 0; i + 1 < g.n; ++i) lp.a[j][i] = -Real(g.a[i][j] - g.a[g.n - 1][j]); lp.a[j][g.n - 1] = 1; lp.b[j] = Real(g.a[g.n - 1][j] - low); if (normalize_rows) { auto absolute = [](const Real& x) { return x < 0 ? -x : x; }; Real scale = std::max(1, absolute(lp.b[j])); for (const Real& x : lp.a[j]) scale = std::max(scale, absolute(x)); for (Real& x : lp.a[j]) x /= scale; lp.b[j] /= scale; } } for (int i = 0; i + 1 < g.n; ++i) lp.a[g.m][i] = 1; lp.b[g.m] = 1; return lp; } inline Game negated_transpose(const Game& g) { Game h; h.n = g.m; h.m = g.n; h.a.assign(h.n, std::vector(h.m)); for (int i = 0; i < g.n; ++i) for (int j = 0; j < g.m; ++j) h.a[j][i] = -g.a[i][j]; return h; } // END expanded game_lp.hpp int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int tests; if (!(std::cin >> tests)) return 0; for (int test = 0; test < tests; ++test) { Game g; read_game(g); const i64 shift = shift_amount(g); auto lp = make_shifted_reciprocal_lp(g, shift); TableauSimplex solver(lp.a, lp.b, lp.c); std::vector y; const long double z = solver.solve(y); const long double answer = 1 / z - shift; std::cout << std::fixed << std::setprecision(15) << answer << '\n'; } }