/** * code generated by JHelper * More info: https://github.com/AlexeyDmitriev/JHelper * @author RiaD */ #include #include #include #define MAKE_CONSTANT(name, type) \ struct name { \ static type value; \ }; \ type name::value; #include #include #include #ifndef SPCPPL_ASSERT #ifdef SPCPPL_DEBUG #define SPCPPL_ASSERT(condition) \ if(!(condition)) { \ throw std::runtime_error(std::string() + #condition + " in line " + std::to_string(__LINE__) + " in " + __PRETTY_FUNCTION__); \ } #else #define SPCPPL_ASSERT(condition) #endif #endif /** * Support decrementing and multi-passing, but not declared bidirectional(or even forward) because * it's reference type is not a reference. * * It doesn't return reference because * 1. Anyway it'll not satisfy requirement [forward.iterators]/6 * If a and b are both dereferenceable, then a == b if and only if *a and * b are bound to the same object. * 2. It'll not work with reverse_iterator that returns operator * of temporary which is temporary for this iterator * * Note, reverse_iterator is not guaranteed to work now too since it works only with bidirectional iterators, * but it's seems to work at least on my implementation. * * It's not really useful anywhere except iterating anyway. */ template class IntegerIterator: public std::iterator { public: explicit IntegerIterator(T value): value(value) { } IntegerIterator& operator++() { ++value; return *this; } IntegerIterator operator++(int) { IntegerIterator copy = *this; ++value; return copy; } IntegerIterator& operator--() { --value; return *this; } IntegerIterator operator--(int) { IntegerIterator copy = *this; --value; return copy; } T operator*() const { return value; } bool operator==(IntegerIterator rhs) const { return value == rhs.value; } bool operator!=(IntegerIterator rhs) const { return !(*this == rhs); } private: T value; }; template class IntegerRange { public: IntegerRange(T begin, T end): begin_(begin), end_(end) { SPCPPL_ASSERT(begin <= end); } IntegerIterator begin() const { return IntegerIterator(begin_); } IntegerIterator end() const { return IntegerIterator(end_); } private: T begin_; T end_; }; template class ReversedIntegerRange { typedef std::reverse_iterator> IteratorType; public: ReversedIntegerRange(T begin, T end): begin_(begin), end_(end) { SPCPPL_ASSERT(begin >= end); } IteratorType begin() const { return IteratorType(IntegerIterator(begin_)); } IteratorType end() const { return IteratorType(IntegerIterator(end_)); } private: T begin_; T end_; }; template IntegerRange range(T to) { return IntegerRange(0, to); } template IntegerRange range(T from, T to) { return IntegerRange(from, to); } template IntegerRange inclusiveRange(T to) { return IntegerRange(0, to + 1); } template IntegerRange inclusiveRange(T from, T to) { return IntegerRange(from, to + 1); } template ReversedIntegerRange downrange(T from) { return ReversedIntegerRange(from, 0); } template ReversedIntegerRange downrange(T from, T to) { return ReversedIntegerRange(from, to); } template ReversedIntegerRange inclusiveDownrange(T from) { return ReversedIntegerRange(from + 1, 0); } template ReversedIntegerRange inclusiveDownrange(T from, T to) { return ReversedIntegerRange(from + 1, to); } #include #include namespace impl { template void matrixMultiplication(const T& lhs, const U& rhs, V& res) { const auto& a = lhs; auto b = rhs.transposed(); for (std::size_t i = 0; i < lhs.rows(); ++i) { for (std::size_t j = 0; j < rhs.columns(); ++j) { for (std::size_t k = 0; k < rhs.rows(); ++k) { res[i][j] += a[i][k] * b[j][k]; } } } } } // namespace impl #include template struct IdentityHelper; template struct IdentityHelper::type> { static T identity() { return 1; } }; template T identity() { return IdentityHelper::identity(); } template struct MakeVector { template < typename... Args, typename R = std::vector::make_vector(std::declval()...))> > static R make_vector(std::size_t first, Args... sizes) { auto inner = MakeVector::make_vector(sizes...); return R(first, inner); } }; template struct MakeVector { /* * This template is to fool CLion. * Without it CLion thinks that make_vector always returns std::vector and marks code like * * auto dp = make_vector(n, m, 0); * dp[0][0] = 1 as error because it suppose that dp[0] is int * * TODO: Consider removing it once https://youtrack.jetbrains.com/issue/CPP-3340 is fixed */ template > static R make_vector(std::size_t size, const T& value) { return R(size, value); } }; template auto make_vector(Args... args) -> decltype(MakeVector::make_vector(args...)) { return MakeVector::make_vector(args...); } template class Matrix { public: explicit Matrix(const T& value = T()): value(make_vector(rows(), columns(), value)) { } std::size_t rows() const { return N::value; } std::size_t columns() const { return M::value; } std::vector& operator[](std::size_t index) { SPCPPL_ASSERT(index < rows()); return value[index]; } const std::vector& operator[](std::size_t index) const { SPCPPL_ASSERT(index < rows()); return value[index]; } Matrix& operator*=(const Matrix& rhs) { return *this = *this * rhs; } Matrix& operator+=(const Matrix& rhs) { for (std::size_t i = 0; i < rows(); ++i) { for (std::size_t j = 0; j < columns(); ++j) { value[i][j] += rhs.value[i][j]; } } return *this; } Matrix operator-() const { Matrix copy = *this; for (int i = 0; i < rows(); ++i) { for (int j = 0; j < columns(); ++j) { copy[i][j] = -copy[i][j]; } } return copy; } Matrix operator-=(const Matrix& rhs) { return *this += -rhs; } Matrix transposed() const { Matrix res; for (std::size_t i = 0; i < rows(); ++i) { for (std::size_t j = 0; j < columns(); ++j) { res[j][i] = value[i][j]; } } return res; } private: std::vector> value; template friend bool operator==(const Matrix& lhs, const Matrix& rhs); }; template bool operator==(const Matrix& lhs, const Matrix& rhs) { return lhs.value == rhs.value; } template Matrix operator*(const Matrix& lhs, const Matrix& rhs) { Matrix res; impl::matrixMultiplication(lhs, rhs, res); return res; } template Matrix operator+(Matrix lhs, const Matrix& rhs) { Matrix copy = std::move(lhs); return copy += rhs; } template Matrix operator-(Matrix lhs, const Matrix& rhs) { Matrix copy = std::move(lhs); return copy -= rhs; } template struct IdentityHelper> { static Matrix identity() { Matrix res; for (std::size_t i = 0; i < N::value; ++i) { res[i][i] = ::identity(); } return res; } }; template using FixedSizeMatrix = Matrix, std::integral_constant>; #include using namespace std; MAKE_CONSTANT(NM, size_t); class FrogInMaze { public: void solve(std::istream& in, std::ostream& out) { int n, m, k; in >> n >> m >> k; NM::value = (size_t) (n * m); using M = Matrix; M matrix; vector s(n); for (int i: range(n)) { in >> s[i]; } map, pair> v; for (int i: range(k)) { int a, b, c, d; in >> a >> b >> c >> d; --a, --b, --c, --d; v[{a, b}] = {c, d}; v[{c, d}] = {a, b}; } int startPos = -1; auto id = [&](int i, int j) { return i * m + j; }; for (int i: range(n)) { for (int j: range(m)) { if (s[i][j] == '#') { continue; } if (s[i][j] == '*') { continue; } if (s[i][j] == '%') { matrix[id(i, j)][id(i, j)] = 1; continue; } if (s[i][j] == 'A') { startPos = id(i, j); } int dx[] = {-1, 1, 0, 0}; int dy[] = {0, 0, 1, -1}; int cnt = 0; for (int d = 0; d < 4; ++d) { int nx = dx[d] + i; int ny = dy[d] + j; if (nx < 0 || nx >= n || ny < 0 || ny >= m || s[nx][ny] == '#') { continue; } ++cnt; } if (cnt == 0) { continue; } for (int d = 0; d < 4; ++d) { int nx = dx[d] + i; int ny = dy[d] + j; if (nx < 0 || nx >= n || ny < 0 || ny >= m|| s[nx][ny] == '#') { continue; } pair to = v.count({nx, ny}) ? v[{nx, ny}] : (pair{nx, ny}); matrix[id(i, j)][id(to.first, to.second)] = 1.0 / cnt; } } } //for (int i: range(n * m)) { // for (int j: range(n * m)) { // out << matrix[i][j] << " "; // } // out << "\n"; //} for (int i: range(n * m > 300 ? 16 : 20)) { matrix = matrix * matrix; } //out << "\n"; // //for (int i: range(n * m)) { // for (int j: range(n * m)) { // out << matrix[i][j] << " "; // } // out << "\n"; //} double ans = 0; for (int i: range(n)) { for (int j: range(m)) { if (s[i][j] == '%') { ans += matrix[startPos][id(i, j)]; } } } out << ans << "\n"; } }; int main() { std::ios_base::sync_with_stdio(false); FrogInMaze solver; std::istream& in(std::cin); std::ostream& out(std::cout); in.tie(0); out << std::fixed; out.precision(20); solver.solve(in, out); return 0; }