/** * code generated by JHelper * More info: https://github.com/AlexeyDmitriev/JHelper * @author RiaD */ #include <iostream> #include <fstream> #include <iostream> #define MAKE_CONSTANT(name, type) \ struct name { \ static type value; \ }; \ type name::value; #include <iterator> #include <string> #include <stdexcept> #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 <typename T> class IntegerIterator: public std::iterator<std::input_iterator_tag, T, std::ptrdiff_t, T*, T> { 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 <typename T> class IntegerRange { public: IntegerRange(T begin, T end): begin_(begin), end_(end) { SPCPPL_ASSERT(begin <= end); } IntegerIterator<T> begin() const { return IntegerIterator<T>(begin_); } IntegerIterator<T> end() const { return IntegerIterator<T>(end_); } private: T begin_; T end_; }; template <typename T> class ReversedIntegerRange { typedef std::reverse_iterator<IntegerIterator<T>> IteratorType; public: ReversedIntegerRange(T begin, T end): begin_(begin), end_(end) { SPCPPL_ASSERT(begin >= end); } IteratorType begin() const { return IteratorType(IntegerIterator<T>(begin_)); } IteratorType end() const { return IteratorType(IntegerIterator<T>(end_)); } private: T begin_; T end_; }; template <typename T> IntegerRange<T> range(T to) { return IntegerRange<T>(0, to); } template <typename T> IntegerRange<T> range(T from, T to) { return IntegerRange<T>(from, to); } template <typename T> IntegerRange<T> inclusiveRange(T to) { return IntegerRange<T>(0, to + 1); } template <typename T> IntegerRange<T> inclusiveRange(T from, T to) { return IntegerRange<T>(from, to + 1); } template <typename T> ReversedIntegerRange<T> downrange(T from) { return ReversedIntegerRange<T>(from, 0); } template <typename T> ReversedIntegerRange<T> downrange(T from, T to) { return ReversedIntegerRange<T>(from, to); } template <typename T> ReversedIntegerRange<T> inclusiveDownrange(T from) { return ReversedIntegerRange<T>(from + 1, 0); } template <typename T> ReversedIntegerRange<T> inclusiveDownrange(T from, T to) { return ReversedIntegerRange<T>(from + 1, to); } #include <vector> #include <cstddef> namespace impl { template <typename T, typename U, typename V> 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 <type_traits> template <typename T, typename = std::true_type> struct IdentityHelper; template <typename T> struct IdentityHelper<T, typename std::is_arithmetic<T>::type> { static T identity() { return 1; } }; template <typename T> T identity() { return IdentityHelper<T>::identity(); } template <typename T, size_t N> struct MakeVector { template < typename... Args, typename R = std::vector<decltype(MakeVector<T, N - 1>::make_vector(std::declval<Args>()...))> > static R make_vector(std::size_t first, Args... sizes) { auto inner = MakeVector<T, N - 1>::make_vector(sizes...); return R(first, inner); } }; template <typename T> struct MakeVector<T, 1> { /* * This template is to fool CLion. * Without it CLion thinks that make_vector always returns std::vector<T> and marks code like * * auto dp = make_vector<int>(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 <typename R = std::vector<T>> static R make_vector(std::size_t size, const T& value) { return R(size, value); } }; template <typename T, typename... Args> auto make_vector(Args... args) -> decltype(MakeVector<T, sizeof...(Args) - 1>::make_vector(args...)) { return MakeVector<T, sizeof...(Args) - 1>::make_vector(args...); } template <typename T, typename N, typename M> class Matrix { public: explicit Matrix(const T& value = T()): value(make_vector<T>(rows(), columns(), value)) { } std::size_t rows() const { return N::value; } std::size_t columns() const { return M::value; } std::vector<T>& operator[](std::size_t index) { SPCPPL_ASSERT(index < rows()); return value[index]; } const std::vector<T>& operator[](std::size_t index) const { SPCPPL_ASSERT(index < rows()); return value[index]; } Matrix& operator*=(const Matrix<T, M, M>& 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<T, M, N> transposed() const { Matrix<T, M, N> 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<std::vector<T>> value; template <typename U, typename V, typename W> friend bool operator==(const Matrix<U, V, W>& lhs, const Matrix<U, V, W>& rhs); }; template <typename T, typename N, typename M> bool operator==(const Matrix<T, N, M>& lhs, const Matrix<T, N, M>& rhs) { return lhs.value == rhs.value; } template <typename T, typename N, typename M, typename K> Matrix<T, N, K> operator*(const Matrix<T, N, M>& lhs, const Matrix<T, M, K>& rhs) { Matrix<T, N, K> res; impl::matrixMultiplication(lhs, rhs, res); return res; } template <typename T, typename N, typename M> Matrix<T, N, M> operator+(Matrix<T, N, M> lhs, const Matrix<T, N, M>& rhs) { Matrix<T, N, M> copy = std::move(lhs); return copy += rhs; } template <typename T, typename N, typename M> Matrix<T, N, M> operator-(Matrix<T, N, M> lhs, const Matrix<T, N, M>& rhs) { Matrix<T, N, M> copy = std::move(lhs); return copy -= rhs; } template <typename T, typename N> struct IdentityHelper<Matrix<T, N, N>> { static Matrix<T, N, N> identity() { Matrix<T, N, N> res; for (std::size_t i = 0; i < N::value; ++i) { res[i][i] = ::identity<T>(); } return res; } }; template <typename T, std::size_t n, std::size_t m> using FixedSizeMatrix = Matrix<T, std::integral_constant<std::size_t, n>, std::integral_constant<std::size_t, m>>; #include <map> 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<double, NM, NM>; M matrix; vector<string> s(n); for (int i: range(n)) { in >> s[i]; } map<pair<int, int>, pair<int, int>> 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<int, int> to = v.count({nx, ny}) ? v[{nx, ny}] : (pair<int, int>{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; }