1. 程式人生 > >清北學堂模擬賽d6t6 棋盤迷宮

清北學堂模擬賽d6t6 棋盤迷宮

bsp 存在 urn 時間 algorithm 個人 board set 個數

3.棋盤迷宮
(boardgame.pas/c/cpp)
(boardgame.in/out)
時間限制:5s/空間限制:256M
【題目描述】
小 A 和小 Z 是非常要好的朋友, 而且他們都對迷宮遊戲非常有興趣。 他們經
常在自習課上用迷宮來打發時間(兩位都是學習效率 400%的 dalao, 大家切記不
要模仿) 。
他們的迷宮非常簡單, 又被他們叫做是棋盤迷宮, 迷宮本身是一個 N*M 大小
的棋盤, 從左往右列數不斷加大, 從上往下行數不斷增大, 故左上角的坐標為(1,
1),右下角的坐標為(N,M) 。 當你處在坐標為(X,Y) 的格子裏時, 你只能走到
(X+1,Y) 或(X,Y+1) , 即只能往右走或者往下走(當然你也不能走出棋盤) 。
同時部分格子中有障礙物, 這樣的格子是不能經過的, 用‘#’ 代表, 能正常通
行的格子由‘.’ 代表。
每一輪遊戲先由其中一人選定起點和終點, 由另外一個人來完成) 。 但是他
們很快發現, 並不是每次都能找到一條從起點到達終點的路徑, 兩位 dalao 的註
意力立刻從遊戲轉移到了如何快速判斷路徑是否存在這個問題上。
當然 dalao 們瞬間得到了算法, 不過他想考考你, 如果你能順利解決, 也許
就能得到他們兩個的簽名哦! (據說是最高級別的因果律護身符, 能讓人逢考必
過)
【輸入格式】 (boardgame.in)
一共 N ? Q ? 2 行。
第一行兩個正整數為 N, M , 表示棋盤迷宮的行列。
接下來 N 行, 每行一個長度為 M 的字符串, 由‘#’ ‘.’ 兩種字符組成
接下來 1 行, 一個正整數 Q ,表示詢問的個數
接下來 Q 行, 每行四個正整數 x1,y1,x2,y2 詢問點(x1,y1) 到(x2,y2) 是
否有一條合法的路徑
數據保證(x1,y1) (x2,y2) 所在的位置都是‘.’ , 同時 x1<=x2,y1<=y2
【輸出格式】 (boardgame.out)
一共 Q 行, 每行一個字符串Yes 或者 No , 對應每一個詢問的答案。
技術分享

技術分享

分析:思路比較新奇的一道題。在線做是做不到滿分的,只有離線了看看多組詢問有什麽特征.如果詢問點對一個點在圖的上半部分,一個點在圖的下半部分,那麽它們之間的路徑肯定要經過中間.考慮一個類似meet in the middle的思想,我們從中間那條線上的點分別向上和向下延伸,看看它能到達哪些點,這樣就能處理點對上的點分布在上下兩個半圖的情況,如果不在同一半圖怎麽辦呢?分治遞歸就可以了.因為最後點對的兩個點肯定要經過中間這條線上的同一個點,所以我們記錄f[i][j][k]來表示(i,j)能夠到達中間線上的哪些點(k是狀態),最後利用二進制處理一下就好了.標程用了bitset,學了一下,似乎挺好用的.

超多組詢問問題我人為要麽就是預處理一下,要麽就是詢問之間肯定有公共類似的部分,從這個公共部分出發,就能通過枚舉少數解得到多數解.

#include <cstdio>
#include <bitset>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int n, m, q, flag[600010];
char s[510][510];
bitset <520> f[520
][520], g[520][520]; struct node { int x1, y1, x2, y2, id; }; void dfs(vector <node> v, int l, int r) { if (l > r) return; int mid = (l + r) >> 1; for (int i = mid; i >= l; i--) //從合法狀態擴展到合法狀態,必須倒著枚舉 for (int j = m; j >= 1; j--) { f[i][j] = 0; if (s[i][j] == .) { if (i == mid) 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 = mid; i <= r; i++) for (int j = 1; j <= m; j++) { g[i][j] = 0; if (s[i][j] == .) { if (i == mid) g[i][j].set(j); else g[i][j] |= g[i - 1][j]; if (j != 1) g[i][j] |= g[i][j - 1]; } } vector <node> vl, vr; for (vector <node>::iterator it = v.begin(); it != v.end(); it++) { node q = *it; if (q.x2 < mid) vl.push_back(q); else if (q.x1 > mid) vr.push_back(q); else flag[q.id] = (f[q.x1][q.y1] & g[q.x2][q.y2]).any(); } dfs(vl, l, mid - 1); dfs(vr, mid + 1, r); } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%s", s[i] + 1); vector <node> v; scanf("%d", &q); for (int i = 1; i <= q; i++) { node temp; scanf("%d%d%d%d", &temp.x1, &temp.y1, &temp.x2, &temp.y2); temp.id = i; v.push_back(temp); } dfs(v, 1, n); for (int i = 1; i <= q; i++) { if (flag[i]) printf("Yes\n"); else printf("No\n"); } return 0; }

清北學堂模擬賽d6t6 棋盤迷宮