zoukankan      html  css  js  c++  java
  • 3.31考试T2

    题目描述

    有一个(n*m)的地图,把左边界和右边界粘起来使得形成一个圆柱,现在要不断地挖去其中的格子,要求任何时候都存在一条从最上方到最下方的路径(四联通),如果某次操作不满足要求则不做,问最后有多少次操作是成功的。

    题解

    从上到下四联通可以转化成从左到右删去的点不能够八联通,考虑怎么判断是否八联通。

    首先我们将地图复制一遍,左边一份,右边一份,每次在左边和右边依次加入删去的点,然后我们对于删去的点进行维护。

    我们使用并查集维护联通块,每个点的(fa)代表它所在的联通块中删去最早的点。

    如果加入的两个点所在的联通块相同的话,由于这两个点本质上又是一个点,所以就形成了从左到右的八联通通道。

    注意:额外判断(m=1)时,加入任何一个点肯定会导致从左到右删去的点能够八联通。

    #include <iostream>
    #include <cstdio>
    #include <queue>
    using namespace std;
    const int N = 6e5 + 5;
    int n, m, Q, ans, fa[N], cnt, vis[3005][6005], pos[N];
    int nx[10] = {0, 0, 0, 1, 1, 1, -1, -1, -1};
    int ny[10] = {0, 1, -1, 0, 1, -1, 0, 1, -1};
    inline int read()
    {
    	int x = 0, f = 1; char ch = getchar();
    	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
    	return x * f;
    }
    int find(int x) {return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);}
    int way(int x, int y)
    {
    	if(m == 1) return 0; int u, v; cnt ++;
    	for(int k = 1; k <= 2; k ++)
    	{
    		if(k == 1) u = x, v = y; else u = x, v = y + m;
    		for(int i = 1; i <= 8; i ++)
    		{
    			int uu = u + nx[i], vv = v + ny[i];
    			if(uu < 1 || uu > n) continue;
    			if(vv > 2 * m) vv -= 2 * m; else if(vv <= 0) vv += 2 * m;
    			if(vis[uu][vv])
    			{
    				if(k == 1) pos[find(vis[uu][vv])] = cnt;
    				else if(pos[find(vis[uu][vv])] == cnt) return 0;
    			}
    		}
    	}
    	return 1;
    }
    int main()
    {
    	n = read(); m = read(); Q = read(); int x, y;
    	for(int i = 1; i <= 2 * Q; i ++) fa[i] = i;
    	for(int num = 1, u, v; num <= Q; num ++)
    	{
    		x = read(); y = read();
    		if(way(x, y))
    		{
    			vis[x][y] = num; vis[x][y + m] = num + Q;
    			for(int k = 1; k <= 2; k ++)
    			{
    				if(k == 1) u = x, v = y; else u = x, v = y + m;
    				for(int i = 1; i <= 8; i ++)
    				{
    					int uu = u + nx[i], vv = v + ny[i];
    					if(uu < 1 || uu > n) continue;
    					if(vv > 2 * m) vv -= 2 * m; else if(vv <= 0) vv += 2 * m;
    					if(vis[uu][vv]) fa[find(vis[u][v])] = find(vis[uu][vv]);
    				}
    			}
    			ans ++;
    		}
    	}
    	printf("%d
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    领域驱动设计精简版--阅读笔记
    ATM机的面向对象分析--笔记
    第一部分 Spring 基础
    spring in action 5 笔记--spring 实战 第4版和第5版对比
    Redis深度历险
    《Spring in action》之Spring之旅
    递归算法(java)
    java中static学习总结
    浅谈HookSSDT和和Resume(恢复)SSDT
    转---派遣例程与IRP结构
  • 原文地址:https://www.cnblogs.com/Sunny-r/p/12606637.html
Copyright © 2011-2022 走看看