【CZY選講·棋盤迷宮】
阿新 • • 發佈:2017-10-12
ash true 數據 scanf 時間 分治 b-s ron 分開
題目描述
一個N*M的棋盤,’.’表示可以通過,’#’表示不能通過,給出Q個詢問,給定起點和終點,判斷兩點是否聯通,如聯通輸出“Yes”,否則輸出“No”。?
數據範圍
N,M <=500,Q <=10^6。
題解:
①由於存在兩個方向和不可逆性,標記聯通分量的方法不可行
②分治算法。按照行將棋盤一分為二,進行DP處理:
用f[i][j]表示點(i,j)與中線上每個點的聯通性,可用bitset壓位處理。?
轉移方程式:f[i][j]=f[i][j+1]|f[i+1][j]
③離線詢問,將詢問隨著分治區間而分開處理。
④時間復雜度: O(n2*logn)
#include <cstdio> #include <vector> #include <bitset> using std::vector; using std::bitset; const int QUERY_SIZE = 600006; const int MAP_SIZE = 511; int N, M, Q; char map[MAP_SIZE][MAP_SIZE]; int ans[QUERY_SIZE]; bitset<MAP_SIZE> f[MAP_SIZE][MAP_SIZE], g[MAP_SIZE][MAP_SIZE]; struct query { int x1, y1, x2, y2, id; }; query q; void solve(vector<query> v, int l, int r) { int m = (l + r) >> 1; if (l > r) return ; for (int i = m; i >= l; i--) for (int j = M; j >= 1; j--) { f[i][j] = 0; if (map[i][j] == ‘.‘) { if (i == m) f[i][j].set(j); else f[i][j] |= f[i + 1][j]; if (j != M) f[i][j] |= f[i][j + 1]; } } for (int i = m; i <= r; i++) for (int j = 1; j <= M; j++) { g[i][j] = 0; if (map[i][j] == ‘.‘) { if (i == m) g[i][j].set(j); else g[i][j] |= g[i - 1][j]; if (j != 1) g[i][j] |= g[i][j - 1]; } } vector<query> vl, vr; for (vector<query>::iterator it = v.begin(); it != v.end(); it++) { q = *it; if (q.x2 < m) vl.push_back(q); else if (q.x1 > m) vr.push_back(q); else ans[q.id] = (f[q.x1][q.y1] & g[q.x2][q.y2]).any(); } solve(vl, l, m - 1); solve(vr, m + 1, r); } int main() { freopen("boardgame.in", "r", stdin); freopen("boardgame.out", "w", stdout); scanf("%d %d", &N, &M); for (int i = 1; i <= N; i++) scanf("%s", map[i] + 1); vector<query> v; scanf("%d", &Q); for (int i = 0; i < Q; i++) { scanf("%d %d %d %d", &q.x1, &q.y1, &q.x2, &q.y2); q.id = i; v.push_back(q); } solve(v, 1, N); for (int i = 0; i < Q; i++) puts(ans[i] ? "Yes" : "No"); return 0; }//czy020202
那神秘的光芒像暴風雨般凜冽著,大地在無情的追問中幻滅成挽歌,
如夢的迷霧隨著詩篇消逝在遠山…… ————————————汪峰《信仰在空中飄揚》
【CZY選講·棋盤迷宮】