hiho151周*

题目链接

题目大意:依次在给定的三维坐标上垒方块,对于一个新的坐标需满足两个条件

              1:六个方向有相邻的方块或者z==1【题目说明了初始状态是:所有z==0的位置都有方块】

              2:该位置存在一条到无穷远处的路径,即不能被已有的方块包围。

              给定一个序列,问按照这个序列放置方块会不会违反上述两条规则。

              1<=x,y,z<=100  N<=100000

-----------------------------------------------------------------------------------------------------

条件一容易判断。

条件二如果正序处理,则每来一个坐标都需要判断和无穷远处的连通性,复杂度很大。

则反过来处理,首先把空格子合并,分到几个集合里。然后倒着删方块,每删一个方块,就merge一下该

方块及周围的六个空格子,merge完后判断方块所在格子是否和无穷远处联通

#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cmath>
#include <vector>
#include <string>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>

#define MAX(a,b) ((a)>=(b)?(a):(b))
#define MIN(a,b) ((a)<=(b)?(a):(b))
#define OO 0x0fffffff
using namespace std;
const int N = 128;
bool tag[N][N][N];
int father[N*N*N];
int ids[N][N][N];
int xs[100100],ys[100100],zs[100100];
int maxx,maxy,maxz;
int minx,miny,minz;
const int dir[6][3] = {{0,0,1},{0,0,-1},{0,1,0},{0,-1,0},{1,0,0},{-1,0,0}};
bool judge(int x,int y,int z){
    if(z==0) return false;
    if(x<minx) return false;
    if(x>maxx) return false;
    if(y<miny) return false;
    if(y>maxy) return false;
    if(z<minz) return false;
    if(z>maxz) return false;
    return true;
}
int find(int id){
    int fid = father[id];
    if(fid==id) return fid;
    return (father[id]=find(fid));
}
void merge(int a,int b){
    int fa = find(a);
    int fb = find(b);
    if(fa==fb) return ;
    father[fb] = fa;
}


int main(){
    int n,t;
    for(int i=0;i<103;i++) for(int j=0;j<103;j++) for(int k=0;k<103;k++){
        ids[i][j][k] = i*10404+j*102+k;
    }
    for(scanf("%d",&t);t--;){
        cin>>n;
        memset(tag,false,sizeof(tag));
        bool flag = true;
        maxx=maxy=maxz=-OO;
        minx=miny=minz=OO;
        for(int i=0;i<n;i++){
            scanf("%d%d%d",xs+i,ys+i,zs+i);
            maxx=MAX(maxx,xs[i]);maxy=MAX(maxy,ys[i]);maxz=MAX(maxz,zs[i]);
            minx=MIN(minx,xs[i]);miny=MIN(miny,ys[i]);minz=MIN(minz,zs[i]);

            if(tag[xs[i]][ys[i]][zs[i]]) flag = false;
            else if(zs[i]==1){
                tag[xs[i]][ys[i]][zs[i]] = true;
            }
            else{
                for(int d=0;d<6;d++){
                    int tx = xs[i]+dir[d][0];
                    int ty = ys[i]+dir[d][1];
                    int tz = zs[i]+dir[d][2];
                    if(tag[tx][ty][tz]){
                        tag[xs[i]][ys[i]][zs[i]] = true;
                        break;
                    }
                }
                if(!tag[xs[i]][ys[i]][zs[i]]) flag = false;
            }
        }
        if(!flag) puts("No");
        else{
            minx--;miny--;minz--;
            maxx++;maxy++;maxz++;
            for(int id=ids[minx][miny][minz];id<=ids[maxx][maxy][maxz];id++) father[id] = id;
            for(int i=minx;i<=maxx;i++)
            for(int j=miny;j<=maxy;j++)
            for(int k=minz;k<=maxz;k++){
                if((k!=0)&&(!tag[i][j][k])){
                    for(int d=0;d<6;d++){
                        int ti = i+dir[d][0];
                        int tj = j+dir[d][1];
                        int tk = k+dir[d][2];
                        if(judge(ti,tj,tk)&&(!tag[ti][tj][tk])){
                            merge(ids[i][j][k],ids[ti][tj][tk]);
                        }
                    }
                }
            }

            int ancestor = ids[maxx][maxy][maxz];
            for(int i=n-1;i>=0;i--){
                if(!flag) break;
                int curId = ids[xs[i]][ys[i]][zs[i]];
                for(int d=0;d<6;d++){
                     int tx = xs[i]+dir[d][0];
                     int ty = ys[i]+dir[d][1];
                     int tz = zs[i]+dir[d][2];
                     if(judge(tx,ty,tz)&&(!tag[tx][ty][tz])){
                        merge(curId,ids[tx][ty][tz]);
                     }
                }
                if(find(curId)!=find(ancestor)){
                    flag = false;
                }
                else{
                    tag[xs[i]][ys[i]][zs[i]]=false;
                }
            }
            if(!flag) puts("No");
            else puts("Yes");
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/redips-l/p/6893656.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值