NTES 网易游戏笔试题(2018实习笔试题第二题,2018秋招补招第一题)

题目

NTES是网易在纳斯达克股票市场的代号,在财报公布后,NTES的股价接连大涨,创下了历史新高。 下面,我们用四个5x7的点阵来描述NTES这代号。

##....#
#.#...#
#..#..#
#...#.#
#....##

#######
...#...
...#...
...#...
...#...

#######
#......
#######
#......
#######

#######
#......
#######
......#
#######

假设我们认为每个点的周围的8个方向的点都和它是相连的,并且相连在一起的符号“#”我们可以认为在同一个联通分量,则上述四个点阵分别都包含了一个“#”的联通分量。

给定N * M的点阵,点阵只包含“.”和“#”两种符号。在点阵中可能包含了很多的联通分量。那么,在这点阵当中,你能找到多少个和标准的“N”,“T”,“E”,“S”一样的联通分量呢?
下面是点阵中NTES对应的联通分量的一些限制:
❖ N、T、E、S可能被顺时针旋转90度、180度或270度。例如以下的7x11的点阵中,包含了两个完整的T(两个联通分量),一个与前文提到的T方向一致,另一个是顺时针旋转了270度。

#...#######
#......#...
#......#...
#####..#...
#......#...
#..........
#..........

❖ 对于任何一个完整的N、T、E、S对应的联通分量,必须和前面给出的标准的模板一致。即除了旋转外,不多出或者缺少任何一个“#”,否则认为不匹配。例如下图中虽然只包含了一个联通分量(根据八方向相连的定义,(1,7)和(0,6)上的“#”相连),但是其多了一个“#”在位置(1,7),因此,以下点阵中没有任何一个NTES对应的联通分量。

#######.
...#...#
...#....
...#....
...#....

输入描述:
每个输入数据包含一个测试点。
第一行为点阵的大小N,M。其中1<=N<=500,1<=M<=500。
接下来N行,每行包含了M个“.”或“#”的字符,描述了给定的点阵。

输出描述:
输出包括四行,按顺序输出点阵中包含的NTES的数量。

输入例子:
输入样例1:

7 11
#...#######
#......#...
#......#...
#####..#...
#......#...
#..........
#..........

输入样例2:

12 23
#######....#....#######
...#...##....#..#......
#..#...#.#...#..#######
#..#...#..#..#........#
#...#..#...#.#..#######
###....#....##.........
.........#.............
#######....#.##.##....#
......#....#....#.#...#
#######....#....#..#..#
......#....#....#...#.#
#######.#######.#....##

输出例子:
输出样例1:

N: 0
T: 2
E: 0
S: 0

输出样例2:

N: 1
T: 1
E: 1
S: 1

解题思路

(1)获取连通分量;
(2)获取NTES对应的点阵旋转0, 90, 180, 270后的点阵;
(3)将连通分量和点阵作比较;

(2)中的旋转, 二维数组90°旋转可以通过a[i][j] = a[j][n - 1 - i]来完成,这里需要注意的是,如果二维数组的行列不一致,那么在将二维数组旋转时,需以当前二维数组的为n来进行旋转;180°不必通过90°旋转的结果来获取,更简单的办法是将二维数组上下倒置(reverseHorizontal),然后左右倒置(reverseVertical),这样不必去判断a[i][j] = a[j][n - 1 - i]中n的值,270°旋转也可由类似的方法通过90°旋转的结果获得;
(3)连通分量和点阵比较,自己的思路是,每一个字符的点阵,以左上角第一点为原点,可以获取整个点阵其它点的坐标,将这些坐标按序(x坐标为主,y坐标为副排序)存放;然后将连通分量也按照这种方法获取其坐标点序列,然后对两者进行比较即可;
注意:题目说明,连通分量必须和给出的点阵(NTES)完全一致,而不是包含关系,如果前者可以包含后者,那么这里的代码就错了;


代码

机试结束后,写出的代码,可以通过样例,不确定能否AC;

#include <algorithm>
#include <iostream>
#include <vector>

int Rows, Cols;

const char T[5][7] = {
        { '#', '#', '#', '#', '#', '#', '#' },
        { '.', '.', '.', '#', '.', '.', '.' },
        { '.', '.', '.', '#', '.', '.', '.' },
        { '.', '.', '.', '#', '.', '.', '.' },
        { '.', '.', '.', '#', '.', '.', '.' },
};

const char N[5][7] = {
        { '#', '#', '.', '.', '.', '.', '#' },
        { '#', '.', '#', '.', '.', '.', '#' },
        { '#', '.', '.', '#', '.', '.', '#' },
        { '#', '.', '.', '.', '#', '.', '#' },
        { '#', '.', '.', '.', '.', '#', '#' },
};

const char E[5][7] = {
        { '#', '#', '#', '#', '#', '#', '#' },
        { '#', '.', '.', '.', '.', '.', '.' },
        { '#', '#', '#', '#', '#', '#', '#' },
        { '#', '.', '.', '.', '.', '.', '.' },
        { '#', '#', '#', '#', '#', '#', '#' },
};

const char S[5][7] = {
        { '#', '#', '#', '#', '#', '#', '#' },
        { '#', '.', '.', '.', '.', '.', '.' },
        { '#', '#', '#', '#', '#', '#', '#' },
        { '.', '.', '.', '.', '.', '.', '#' },
        { '#', '#', '#', '#', '#', '#', '#' },
};

/************************************************************************/
/* 点阵旋转90°,180°和270° */
std::vector<std::vector<char>> rotate90(const std::vector<std::vector<char>>& arrays){
    int rows = arrays.size();
    int cols = arrays.front().size();
    std::vector<std::vector<char>> result(cols, std::vector<char>(rows));
    for (int i = 0; i < rows; ++i){
        for (int k = 0; k < cols; ++k){
            result[k][rows - 1 - i] = arrays[i][k];
        }
    }
    return result;
}

std::vector<std::vector<char>> reverseVertical(const std::vector<std::vector<char>>& arrays){
    int rows = arrays.size();
    int cols = arrays.front().size();
    std::vector<std::vector<char>> result(rows, std::vector<char>(cols, ' '));
    for (int i = 0; i < rows; ++i){
        for (int k = 0; k < cols; ++k){
            result[rows - 1 - i][k] = arrays[i][k];
        }
    }
    return result;
}

std::vector<std::vector<char>> reverseHorizontal(const std::vector<std::vector<char>>& arrays){
    int rows = arrays.size();
    int cols = arrays.front().size();
    std::vector<std::vector<char>> result(rows, std::vector<char>(cols, ' '));
    for (int i = 0; i < rows; ++i){
        for (int k = 0; k < cols; ++k){
            result[i][cols - 1 - k] = arrays[i][k];
        }
    }
    return result;
}

std::vector<std::vector<char>> rotate180(const std::vector<std::vector<char>>& arrays){
    std::vector<std::vector<char>> result;
    result = reverseHorizontal(arrays);
    result = reverseVertical(result);
    return result;
}

std::vector<std::vector<char>> rotate270(const std::vector<std::vector<char>>& arrays){
    std::vector<std::vector<char>> result;
    result = rotate90(arrays);
    result = reverseHorizontal(result);
    result = reverseVertical(result);
    return result;
}

/************************************************************************/


//记录点在点阵中或输入样例中的位置
struct position{
    position(int x, int y) : x(x), y(y){}
    bool operator==(const position& rhs) const {
        return (x == rhs.x) && (y == rhs.y);
    }
    int x, y;
};

//计算点阵中(char类型)和输入样例中(输入后转化为int类型)的点的坐标
//记录坐标的顺序为从上到下,从左到右(x坐标为主,y坐标为副排序),
//所有点的坐标均是相对第一个点的坐标,第一个点的坐标在其他点处理完毕后,设置为(0, 0)
//由于存在两种类型,故使用模板
template<typename U>
std::vector<position> calcPosition(const std::vector<std::vector<U>>& arrays, int chr = '#')
{
    std::vector<position> result;
    for (int i = 0; i < arrays.size(); ++i){
        for (int k = 0; k < arrays.front().size(); ++k){
            if ((int)arrays[i][k] == chr){
                result.push_back(position(i, k));
            }
        }
    }
    position& firstP = result.front();
    for (int i = 1; i < result.size(); ++i){
        result[i].x -= firstP.x;
        result[i].y -= firstP.y;
    }
    firstP = position(0, 0);
    return result;
}

//比较输入样例中获得的联通分量的坐标点特征和点阵中点的坐标特征是否相同
bool compare(const std::vector<position>& lhs, const std::vector<position>& rhs){
    if (lhs.size() != rhs.size()){
        return false;
    }
    for (int i = 0; i < lhs.size(); ++i){
        if (!(lhs[i] == rhs[i])){
            return false;
        }
    }
    return true;
}

//深度优先搜索,将各个连通分量进行标记,输入时,map中'.'为-1,'#'为0
//各个联通分量分别用1,2,3,...标记
void DFS(std::vector<std::vector<int>>& map, int x, int y, int mark){
    if (x < 0 || x >= Rows || y < 0 || y >= Cols){
        return;
    }
    if (map[x][y] != 0){
        return;
    }
    map[x][y] = mark;
    for (int i = -1; i <= 1; ++i){
        for (int k = -1; k <= 1; ++k){
            DFS(map, x + i, y + k, mark);
        }
    }
}

//以NTES的各个点阵作为输入
//获取该点阵对应的旋转后,点阵中各个点的相对坐标
std::vector<std::vector<position>> calcNTESPosition(const std::vector<std::vector<char>>& chs){
    std::vector<std::vector<position>> result;
    std::vector<position> tmp;
    tmp = calcPosition(chs);
    result.push_back(tmp);
    tmp = calcPosition(rotate90(chs));
    result.push_back(tmp);
    tmp = calcPosition(rotate180(chs));
    result.push_back(tmp);
    tmp = calcPosition(rotate270(chs));
    result.push_back(tmp);

    return result;
}

//将const char [5][7]的原始输入转化为vector存储
std::vector<std::vector<char>> convert(const char (&array)[5][7]){
    std::vector<std::vector<char>> result(sizeof(array) / sizeof(array[0]), std::vector<char>(sizeof(array[0])));
    for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i){
        for (int k = 0; k < sizeof(array[0]); ++k){
            result[i][k] = array[i][k];
        }
    }
    return result;
}

int main()
{
    //获取各个点阵对应的四个点阵的坐标点特征
    std::vector<std::vector<char>> TV = convert(T);
    auto TPositions = calcNTESPosition(TV);
    std::vector<std::vector<char>> NV = convert(N);
    auto NPositions = calcNTESPosition(NV);
    std::vector<std::vector<char>> EV = convert(E);
    auto EPositions = calcNTESPosition(EV);
    std::vector<std::vector<char>> SV = convert(S);
    auto SPositions = calcNTESPosition(SV);

    std::cin >> Rows >> Cols;
    char input;
    std::vector<std::vector<int>> map(Rows, std::vector<int>(Cols, -1));
    for (int i = 0; i < Rows; ++i){
        for (int k = 0; k < Cols; ++k){
            std::cin >> input;
            if (input == '#'){
                map[i][k] = 0;
            }
        }
    }

    //用1,2,3,...标记输入中的各个连通分量
    int mark = 0;
    for (int i = 0; i < Rows; ++i){
        for (int k = 0; k < Cols; ++k){
            if (map[i][k] == 0){
                DFS(map, i, k, ++mark);
            }
        }
    }

    //获取各个连通分量对应的坐标点特征,然后和NTES四个点阵的坐标点特征作比较
    int resultT = 0, resultN = 0, resultE = 0, resultS = 0;
    for (int i = 1; i <= mark; ++i){
        std::vector<position> tmp;
        //在DFS以1~mark标记不同的连通分量,这里获取该连通分量对应的坐标点特征
        tmp = calcPosition(map, i);
        int tmpCount = tmp.size();
        //11,15,23,23分别是T,N,E,S的点阵对应的坐标点数量
        if (tmpCount == 11){
            for (int i = 0; i < TPositions.size(); ++i){
                if (compare(tmp, TPositions[i])){
                    resultT++;
                    break;
                }
            }
        }else if(tmpCount == 15){
            for (int i = 0; i < NPositions.size(); ++i){
                if (compare(tmp, NPositions[i])){
                    resultN++;
                    break;
                }
            }
        }
        else if (tmpCount == 23){
            for (int i = 0; i < EPositions.size(); ++i){
                if (compare(tmp, EPositions[i])){
                    resultE++;
                    break;
                }
            }

            for (int i = 0; i < SPositions.size(); ++i){
                if (compare(tmp, SPositions[i])){
                    resultS++;
                    break;
                }
            }
        }
    }

    std::cout << "N:" << resultN << std::endl;
    std::cout << "T:" << resultT << std::endl;
    std::cout << "E:" << resultE << std::endl;
    std::cout << "S:" << resultS << std::endl;

    system("pause");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值