个人练习-PAT甲级-1091 Acute Stroke

题目链接https://pintia.cn/problem-sets/994805342720868352/problems/994805375457411072

照理讲应该是BFS题,不过偷懒,多开了些数组,想直接扫描输入时就记录结果。写着写着感觉漏缺还是挺多的,但写都写了,总要写写完吧,debug了挺久,最后还是过了,记录下注意点。之后有机会再用BFS版本写一遍。

定义一个坐标的结构体

class Coord {
public:
    int x, y, z;
    Coord() {}
    Coord(int i, int j, int k) {
        x = i; y = j; z = k;
    }
};

一些数组,lump[]是记录stroke块的数组,每一个元素是一个stroke块的vector,stroke块就是空间上连续的stroke点的集合。
g[][][]存某个坐标是否为stroke点
cor2idx[]:输入坐标,得到这个坐标在lump[]数组的哪一个元素里(在哪一个stroke块里)

vector<vector<Coord>> lump;
bool g[1330][130][70];
int cor2idx[1330][130][70];
int M, N, L, T;

初始化所有cor2idx,因为开始时lump[]中什么也没有。

void Init() {
    for (int i = 0; i < M; i++) {
        for (int j = 0; j < N; j++) {
            for (int k = 0; k < L; k++)
                cor2idx[i][j][k] = -1;
        }
    }
}

读入数据,读入一个stroke点就将其加入lump,并给他的cor2idx赋好值。为什么可以这样呢?因为【相邻】的定义是x,y,z方向上分别+1或-1得到的6个坐标,我们每次其实只要考虑-1方向上的3个坐标即可。因为我们扫描的顺序都是x,y,z从小到大的,这样扫描完毕后每个相邻关系其实都可以被探测到。

    for (int k = 0; k < L; k++) {
        for (int i = 0; i < M; i++) {
            for (int j = 0; j < N; j++) {
                scanf("%d", &tmp);
                if (tmp) {
                    g[i][j][k] = true;
                    Add(i, j, k);
                }
            }
        }
    }

重要函数Add(),将stroke点加入lump,并给他的cor2idx赋好值。遍历3个低处的相邻点,如果它们中有stroke点,就将自身合并进去,然后,将自身和3个相邻点(如果是stroke点)都合并进同一个stroke块。这点非常重要,否则会出现这样的特例:
设本身为0,相邻点为1,2,3;三个相邻点都为stroke点;
0和1合并进了1号stroke块(lump[1]);
然而2号还在2号stroke块中(lump[2]),3号还在3号stroke块中(lump[3]);
由于0与1,2,3都是相邻的,它们本应属于同一个stroke块,所以需要把2号和3号合并进lump[1]

换句话说,【一个点若为stroke点,它有可能会把周围的几个stroke块都合并成同一个stroke块】

反之,若三个相邻点都不是stroke点,那么本身自己成为一个stroke块。

void Add(int i, int j, int k) {
    Coord c(i, j, k);
    int px[3] = { -1, 0, 0 };
    int py[3] = { 0, -1, 0 };
    int pz[3] = { 0, 0, -1 };
    int tx, ty, tz;
    bool flag = false;
    for (int cnt = 0; cnt < 3; cnt++) {
        tx = i + px[cnt];
        ty = j + py[cnt];
        tz = k + pz[cnt];
        if (tx >= 0 && tx < M && ty >= 0 && ty < N && tz >= 0 && tz < L) {
            int pos = cor2idx[tx][ty][tz];
            if (pos != -1) {
                flag = true;
                lump[pos].push_back(c);
                cor2idx[i][j][k] = pos;
                break;
            }
        }
    }

    if (!flag) {
        cor2idx[i][j][k] = findEmpty();
        if (cor2idx[i][j][k] == lump.size()) {
            vector<Coord> vc;
            vc.push_back(c);
            lump.push_back(vc);
        }
        else 
            lump[cor2idx[i][j][k]].push_back(c);
        
    }
    else{
        for (int cnt = 0; cnt < 3; cnt++) {
            tx = i + px[cnt];
            ty = j + py[cnt];
            tz = k + pz[cnt];
            if (tx >= 0 && tx < M && ty >= 0 && ty < N && tz >= 0 && tz < L) {
                int m_pos = cor2idx[i][j][k];
                int pos = cor2idx[tx][ty][tz];
                if (pos != -1) {
                    if (pos != m_pos) {
                        if (lump[pos].size() < lump[m_pos].size()) 
                            Merge(pos, m_pos);
                        
                        else 
                            Merge(m_pos, pos);
                            
                        

                    }
                }
            }
        }
    }

}

合并stroke块时我们把小的合并进大的,同时把cor2idx的值改变。并把小的stroke块位置清空(但不要删除,否则所有stroke块的编号全乱了),这个空位可以给新的stroke块使用

void Merge(int p1, int p2) {
    for (int i = 0; i < lump[p1].size(); i++) {
        lump[p2].push_back(lump[p1][i]);
        cor2idx[lump[p1][i].x][lump[p1][i].y][lump[p1][i].z] = p2;
    }
        
    lump[p1].clear();
}

为节省空间,有新的stroke块时,先找找lump[]中是否有空的位置(一次合并后会留下一个空位),有空的就用空的;没有再新开空间。

int findEmpty() {
    int ret;
    for (ret = 0; ret < lump.size(); ret++) {
        if (lump[ret].size() == 0)
            return ret;
    }
    return ret;
}

最后计算,输出即可

    int ret = 0;
    for (int i = 0; i < lump.size(); i++) {
        if (lump[i].size() >= T)
            ret += lump[i].size();
    }

    printf("%d", ret);

完整代码

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
#include<stdio.h>
#include<math.h>
#include<map>
#include<set>
#include<queue>
#include<string.h>

using namespace std;

class Coord {
public:
    int x, y, z;
    Coord() {}
    Coord(int i, int j, int k) {
        x = i; y = j; z = k;
    }
};

vector<vector<Coord>> lump;
bool g[1286][128][60];
int cor2idx[1286][128][60];
int M, N, L, T;


void Init() {
    for (int i = 0; i < M; i++) {
        for (int j = 0; j < N; j++) {
            for (int k = 0; k < L; k++)
                cor2idx[i][j][k] = -1;
        }
    }
}

int findEmpty() {
    int ret;
    for (ret = 0; ret < lump.size(); ret++) {
        if (lump[ret].size() == 0)
            return ret;
    }
    return ret;
}

void Merge(int p1, int p2) {
    for (int i = 0; i < lump[p1].size(); i++) {
        lump[p2].push_back(lump[p1][i]);
        cor2idx[lump[p1][i].x][lump[p1][i].y][lump[p1][i].z] = p2;
    }
        
    lump[p1].clear();
}

void Add(int i, int j, int k) {
    Coord c(i, j, k);
    int px[3] = { -1, 0, 0 };
    int py[3] = { 0, -1, 0 };
    int pz[3] = { 0, 0, -1 };
    int tx, ty, tz;
    bool flag = false;
    for (int cnt = 0; cnt < 3; cnt++) {
        tx = i + px[cnt];
        ty = j + py[cnt];
        tz = k + pz[cnt];
        if (tx >= 0 && tx < M && ty >= 0 && ty < N && tz >= 0 && tz < L) {
            int pos = cor2idx[tx][ty][tz];
            if (pos != -1) {
                flag = true;
                lump[pos].push_back(c);
                cor2idx[i][j][k] = pos;
                break;
            }
        }
    }

    if (!flag) {
        cor2idx[i][j][k] = findEmpty();
        if (cor2idx[i][j][k] == lump.size()) {
            vector<Coord> vc;
            vc.push_back(c);
            lump.push_back(vc);
        }
        else 
            lump[cor2idx[i][j][k]].push_back(c);
        
    }
    else{
        for (int cnt = 0; cnt < 3; cnt++) {
            tx = i + px[cnt];
            ty = j + py[cnt];
            tz = k + pz[cnt];
            if (tx >= 0 && tx < M && ty >= 0 && ty < N && tz >= 0 && tz < L) {
                int m_pos = cor2idx[i][j][k];
                int pos = cor2idx[tx][ty][tz];
                if (pos != -1) {
                    if (pos != m_pos) {
                        if (lump[pos].size() < lump[m_pos].size()) 
                            Merge(pos, m_pos);
                        
                        else 
                            Merge(m_pos, pos);
                            
                        

                    }
                }
            }
        }
    }

}


int main() {
    int tmp;
    scanf("%d %d %d %d", &M, &N, &L, &T);

    Init();

    for (int k = 0; k < L; k++) {
        for (int i = 0; i < M; i++) {
            for (int j = 0; j < N; j++) {
                scanf("%d", &tmp);
                if (tmp) {
                    g[i][j][k] = true;
                    Add(i, j, k);
                }
            }
        }
    }

    
    int ret = 0;
    for (int i = 0; i < lump.size(); i++) {
        if (lump[i].size() >= T)
            ret += lump[i].size();
    }

    printf("%d", ret);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值