C语言编程题_3D接雨水

接雨水的题目描述如下。

(1) 2D接雨水: 字节员工是不是个个都会接雨水 ;

(2) 3D接雨水: 407. 接雨水 II ;

(3) 3D接雨水: 字节人都会的 3D接雨水 。

  问题描述

  难度:困难

  给你一个 m x n 的矩阵,其中的值均为非负整数,代表二维高度图每个单元的高度,请计算图中形状最多能接多少体积的雨水。

  示例1:

  输入:heightMap = [[1,4,3,1,3,2],[3,2,1,3,2,4],[2,3,3,2,3,1]];

  输出:4

  解释:下雨后,雨水将会上图蓝色的方块中。总的接雨水量为1+1+1=4。

  我找到的最好的思路是:把这个看成木桶接水,就像是短板理论。最外层一圈一定接不到水,也就是可以看成木桶的边缘,先把木桶的边缘都放进优先队列中,这时取出最小的柱子,向这个柱子的 4 个方向扩散,扩散出的柱子有两种情况,如果比当前柱子大,那么不能接水,如果比当前柱子小,那么接到的水就是当前柱子高度减去扩散柱子的高度(为什么?因为当前柱子一定是边缘最小的了,所以它一定能接到水),后面在把扩散的柱子加入到优先队列中,已经比较完的柱子就移出队列,这样就又形成了新的桶的边缘,并且水桶面积也在不断缩小(当然要记录走过的柱子,防止重复走),最终就会计算完成。

  下面是用C语言实现的3D接雨水:

#include <stdio.h>
#include <stdlib.h>

#define Cols            (6)
#define Rows            (3)

#define Status_ToDo     (0) // 待处理的。
#define Status_Done     (1) // 已处理的。
#define Status_Border   (2) // 作为木桶板。

int addRainWaterOfTBLR(int height[][Cols], int status[][Cols], int minBorderHeight, int row, int col);

void initStatus(int arr[][Cols]) {
    // // 注: 使用下面语句得到的rowCount为0, 因为arr作为形参的时候就会被当作一个指针。
    // int rowCount = sizeof(arr) / sizeof(arr[0]);
    for (int row = 0; row < Rows; row++) {
        for (int col = 0; col < Cols; col++) {
            if (0 == row || Rows-1 == row || 0 == col || Cols-1 == col) {
                arr[row][col] = Status_Border;
            } else {
                arr[row][col] = Status_ToDo;
            }
        }
    }
    // 去掉四个角。
    arr[0][0] = arr[0][Cols-1] = arr[Rows-1][0] = arr[Rows-1][Cols-1] = Status_Done;
}

void showStatus(int height[][Cols], int status[][Cols]) {
    printf("打印状态:\n");
    for (int row = 0; row < Rows; row++) {
        for (int col = 0; col < Cols; col++) {
            printf("%d(%d), ", height[row][col], status[row][col]);
        }
        printf("\n");
    }
}

void findPositionOfMinBorder(int height[][Cols], int status[][Cols], int result[2]) {
    // printf("findPositionOfMinBorder\n");
    result[0] = 0;
    result[1] = 0;
    for (int row = 0; row < Rows; row++) {
        for (int col = 0; col < Cols; col++) {
            if (Status_Border == status[row][col]
                && ((0 == result[0] && 0 == result[1]) || height[row][col] < height[result[0]][result[1]])
            ) {
                result[0] = row;
                result[1] = col;
            }
        }
    }
    printf("最小板的位置是(%d,%d)\n", result[0], result[1]);
}

void repairBorder(int status[][Cols]) {
    for (int row = 0; row < Rows; row++) {
        for (int col = 0; col < Cols; col++) {
            if (Status_Border == status[row][col]) {
                //上下左右都不是待处理的。
                if ((0 == row || (row > 0 && status[row-1][col] != Status_ToDo))
                    && (Rows-1 == row || (Rows-1 > row && status[row+1][col] != Status_ToDo))
                    && (0 == col || (col > 0 && status[row][col-1] != Status_ToDo))
                    && (Cols-1 == col || (Cols-1 > col && status[row][col+1] != Status_ToDo))
                ) {
                    status[row][col] = Status_Done;
                }
            }
        }
    }
}

int addRainWaterAtPosition(int height[][Cols], int status[][Cols], int minBorderHeight, int row, int col) {
    int result = 0;
    // printf("addRainWaterAtPosition(%d,%d)\n", row, col);
    if (height[row][col] <= minBorderHeight) {
        result += (minBorderHeight - height[row][col]);
        result += addRainWaterOfTBLR(height, status, minBorderHeight, row, col);
    } else {
        status[row][col] = Status_Border;
    }
    return result;
}

int addRainWaterOfTBLR(int height[][Cols], int status[][Cols], int minBorderHeight, int row, int col) {
    int result = 0;
    // printf("addRainWaterOfTBLR(%d,%d)\n", row, col);
    status[row][col] = Status_Done;
    if (row > 0 && Status_ToDo == status[row-1][col]) { // 上。
        result += addRainWaterAtPosition(height, status, minBorderHeight, row-1, col);
    }
    if (row < Rows-1 && Status_ToDo == status[row+1][col]) { // 下。
        result += addRainWaterAtPosition(height, status, minBorderHeight, row+1, col);
    }
    if (col > 0 && Status_ToDo == status[row][col-1]) { // 左。
        result += addRainWaterAtPosition(height, status, minBorderHeight, row, col-1);
    }
    if (col < Cols-1 && Status_ToDo == status[row][col+1]) { // 右。
        result += addRainWaterAtPosition(height, status, minBorderHeight, row, col+1);
    }
    return result;
}

// 判断完成。
int checkFinish(int status[][Cols]) {
    for (int row = 0; row < Rows; row++) {
        for (int col = 0; col < Cols; col++) {
            if (Status_ToDo == status[row][col]) {
                return 0;
            }
        }
    }
    return 1;
}

// 简介:  3D接雨水。
int main(void)
{
    int rainWater = 0;
    int heightMap[][Cols] = {{1,4,3,1,3,2},{3,2,1,3,2,4},{2,3,3,2,3,1}};
    // printf("heightMap_rowCount = %d。\n", sizeof(heightMap) / sizeof(heightMap[0]));
    int (*status)[Cols] = malloc(sizeof(int) * (sizeof(heightMap) / sizeof(heightMap[0])) * Cols);
    initStatus(status);
    showStatus(heightMap, status);

    while(!checkFinish(status)) {
        int positionOfMinBorder[2] = {0, 0};
        findPositionOfMinBorder(heightMap, status, positionOfMinBorder);
        int minBorderHeight = heightMap[positionOfMinBorder[0]][positionOfMinBorder[1]];
        // printf("minBorderHeight=%d\n", minBorderHeight);
        rainWater += addRainWaterOfTBLR(heightMap, status, minBorderHeight, positionOfMinBorder[0], positionOfMinBorder[1]);
        repairBorder(status);
        showStatus(heightMap, status);
    }
    printf("总的接雨水量为%d\n", rainWater);

    free(status);

    printf("程序正常退出。\n");
    return 0;
}

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值