• 【CZY选讲·棋盘迷宫】


    题目描述

    一个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

    那神秘的光芒像暴风雨般凛冽着,大地在无情的追问中幻灭成挽歌,

    如梦的迷雾随着诗篇消逝在远山…… ————————————汪峰《信仰在空中飘扬》

  • 相关阅读:
    零点起飞学FlashCS6动画制作
    注意 方法的执行 顺序,并且 如果 为 nil的话,bool类型的数据 也默认是有值的,
    datepicker 的一个属性,
    用户体验 的一个原则,
    break 一下 便会 跳出 整个 switch ,
    原来 同一个 bundleid的项目 的下面 可以 通过这个 解决,诡异的问题,
    section 和 row,
    缓存,plist 和 json
    本地通知,UILocalNotification
    bundle id
  • 原文地址:https://www.cnblogs.com/Damitu/p/7654448.html
Copyright © 2020-2023  润新知