#include #include #include #include #include #include #include #include #include #include #include using namespace std; typedef int64_t int64; // BEGIN CUT #define DBG(x) #x << " = " << x #define REP(i,n) for (int i = 0; i < (n); i++) #define REPV(i,v) for (size_t i = 0; i < v.size(); i++) #define ALL(x) (x).begin(), (x).end() #define SORT(x) sort(ALL(x)) #define UNIQUE(x) SORT(x), x.resize(unique(ALL(x)) - x.begin()) #define pb push_back template ostream& operator <<(ostream& os, const pair& v) { os << "(" << v.first << " " << v.second << ")"; return os; } template ::value>::type> ostream& operator<<(ostream& os, const T& v) { os << '['; for (const auto& it : v) os << it << " "; if (!v.empty()) os << "\b"; os << "]"; return os; } // END CUT inline void operator/=(vector& v, double c) { REPV(i, v) v[i] /= c; } inline void operator-=(vector& v, const vector u) { REPV(i, v) v[i] -= u[i]; } inline vector operator*(double c, const vector v) { vector res = v; REPV(i, res) res[i] *= c; return res; } double fabs(double x) { return x < 0 ? -x : x; } int H, W, K; vector> src, dst; vector maze; map tunnel; int alef_r, alef_c, alef_v; bool can_go(int r, int c) { if (r < 0 || r >= H || c < 0 || c >= W) return false; if (maze[r][c] == '#') return false; return true; } int get(int v) { if (tunnel.count(v)) return tunnel[v]; return v; } bool can_exit() { unordered_set visited; queue q; q.push(alef_v); while (!q.empty()) { int v = q.front(); q.pop(); v = get(v); if (visited.count(v)) continue; visited.insert(v); int r = v / W, c = v % W; if (maze[r][c] == '*') continue; if (maze[r][c] == '%') return true; if (can_go(r-1, c)) q.push(v - W); if (can_go(r+1, c)) q.push(v + W); if (can_go(r, c-1)) q.push(v - 1); if (can_go(r, c+1)) q.push(v + 1); } return false; } int main() { #ifdef LocalHost freopen("input.txt", "rt", stdin); #endif cin.tie(0); ios_base::sync_with_stdio(0); cin >> H >> W >> K; maze.resize(H); REP(i, H) cin >> maze[i]; REP(i, K) { int r1, c1, r2, c2; cin >> r1 >> c1 >> r2 >> c2; r1--, c1--, r2--, c2--; tunnel[r1*W + c1] = r2*W + c2; tunnel[r2*W + c2] = r1*W + c1; } REP(r, H) REP(c, W) if (maze[r][c] == 'A') { alef_r = r; alef_c = c; maze[r][c] = '0'; } alef_v = alef_r * W + alef_c; if (!can_exit()) { cout << 0 << endl; return 0; } vector> matr; int HW = H*W; REP(r, H) REP(c, W) { char ch = maze[r][c]; if (ch == '#') continue; vector row(HW+1); row[r*W + c] = 1; if (ch == '*') { row[HW] = 0; matr.pb(row); continue; } if (ch == '%') { row[HW] = 1; matr.pb(row); continue; } int v = r*W + c; int k = 0; if (can_go(r-1, c)) k++, row[get(v-W)] = -1; if (can_go(r+1, c)) k++, row[get(v+W)] = -1; if (can_go(r, c-1)) k++, row[get(v-1)] = -1; if (can_go(r, c+1)) k++, row[get(v+1)] = -1; if (k == 0) row[HW] = 0; else row[v] = k; matr.pb(row); } // cerr << get(alef_v - 1) << endl; // cerr << tunnel << endl; // cerr << "matr has " << matr.size() << " rows:" << endl; // REPV(i, matr) // cerr << matr[i] << endl; // cerr << endl; size_t k = 0; REP(i, HW) { int found = -1; for (size_t j = k; j < matr.size(); j++) { if (fabs(matr[j][i]) > 1e-8) { found = j; break; } } if (found == -1) continue; matr[k].swap(matr[found]); matr[k] /= matr[k][i]; REPV(j, matr) if (j != k) matr[j] -= (matr[j][i] * matr[k]); k++; } REPV(i, matr) if (fabs(matr[i][alef_v]) > 1e-9) { cout << matr[i][HW] << endl; return 0; } return 0; }