UVa 1030 Image Is Everything

题目描述

你的公司正在建造一个能够抓取小型轻量物体的机器人。机器人需要通过智能判断来确定物体是否足够轻。它通过从666个基本方向(前、后、左、右、上、下)拍摄物体的图片,然后根据这些图像推断物体重量的上限。

每个物体由一个 N×N×NN \times N \times NN×N×N 的立方体网格组成,其中某些立方体可能缺失。每个 1×1×11 \times 1 \times 11×1×1 的立方体重111克,每个立方体被涂成单一纯色。物体不一定是连通的。

输入格式

输入包含多个测试用例。每个测试用例以一行包含整数 NNN (1≤N≤101 \leq N \leq 101≤N≤10) 开始,表示物体的大小。接下来的 NNN 行包含666个不同的 N×NN \times NN×N 视图,按顺序为:前、左、后、右、顶、底视图。每个视图与下一个视图之间用单个空格分隔。

输出格式

对于每个测试用例,输出一行包含物体的最大可能重量,格式如样例所示。

题目分析

问题理解

我们需要根据666个正交投影视图来重构一个 N×N×NN \times N \times NN×N×N 的三维物体,并找出在满足所有视图约束的情况下,物体可能包含的最大立方体数量。

关键约束条件:

  • 每个视图是一个 N×NN \times NN×N 的网格
  • 网格中的每个位置要么是颜色字母,表示从该方向看过去时,该位置看到的第一个不透明立方体的颜色
  • 网格中的 '.' 表示从该方向看过去,该位置没有立方体(即整条视线都是透明的)

核心思路

这是一个三维几何约束满足问题 ,我们可以通过迭代约束传播的方法来解决。

算法步骤
  1. 初始化 :假设所有 N3N^3N3 个立方体都存在
  2. 处理透明约束:对于每个视图中为 '.' 的位置,移除该视线上的所有立方体
  3. 迭代处理颜色约束
    • 对于每个视图中为颜色的位置,沿着视线方向找到第一个存在的立方体
    • 如果该立方体颜色未确定,设置为视图颜色
    • 如果颜色匹配,处理完成
    • 如果颜色冲突,移除该立方体并继续寻找
  4. 重复步骤3直到没有立方体状态发生变化
  5. 统计结果:计算剩余立方体数量
坐标映射

关键的难点在于正确建立666个视图与三维立方体坐标之间的映射关系:

  • 前视图 (−z-z−z 方向):(x,y,z)=(c,N−1−r,d)(x, y, z) = (c, N-1-r, d)(x,y,z)=(c,N−1−r,d)
  • 左视图 (−x-x−x 方向):(x,y,z)=(d,N−1−r,N−1−c)(x, y, z) = (d, N-1-r, N-1-c)(x,y,z)=(d,N−1−r,N−1−c)
  • 后视图 (+z+z+z 方向):(x,y,z)=(N−1−c,N−1−r,N−1−d)(x, y, z) = (N-1-c, N-1-r, N-1-d)(x,y,z)=(N−1−c,N−1−r,N−1−d)
  • 右视图 (+x+x+x 方向):(x,y,z)=(N−1−d,N−1−r,c)(x, y, z) = (N-1-d, N-1-r, c)(x,y,z)=(N−1−d,N−1−r,c)
  • 顶视图 (+y+y+y 方向):(x,y,z)=(c,N−1−d,N−1−r)(x, y, z) = (c, N-1-d, N-1-r)(x,y,z)=(c,N−1−d,N−1−r)
  • 底视图 (−y-y−y 方向):(x,y,z)=(c,d,r)(x, y, z) = (c, d, r)(x,y,z)=(c,d,r)

其中 (r,c)(r, c)(r,c) 是视图坐标,ddd 是视线深度。

复杂度分析

  • 空间复杂度 :O(N3)O(N^3)O(N3),用于存储三维立方体状态
  • 时间复杂度 :最坏情况下 O(N5)O(N^5)O(N5),但由于 N≤10N \leq 10N≤10,实际运行效率很高

代码实现

cpp 复制代码
// Image Is Everything
// UVa ID: 1030
// Verdict: Accepted
// Submission Date: 2025-10-24
// UVa Run Time: 0.000s
//
// 版权所有(C)2025,邱秋。metaphysis # yeah dot net

#include <bits/stdc++.h>

using namespace std;

const int MAX_CUBE_SIZE = 15;  // 最大立方体尺寸

class CubeReconstructor {
private:
    int cubeSize;                          // 立方体的尺寸 N
    char viewData[6][MAX_CUBE_SIZE][MAX_CUBE_SIZE];  // 存储6个方向的视图数据
    char cubeState[MAX_CUBE_SIZE][MAX_CUBE_SIZE][MAX_CUBE_SIZE];  // 三维立方体状态
    
    /**
     * 读取有效字符,跳过空格等无效字符
     * @return 有效的颜色字符(大写字母)或 '.' 表示透明
     */
    char readValidCharacter() {
        char currentChar;
        while (true) {
            currentChar = getchar();
            // 只接受大写字母(颜色)或 '.'(透明)
            if ((currentChar >= 'A' && currentChar <= 'Z') || currentChar == '.') {
                return currentChar;
            }
        }
    }
    
    /**
     * 将视图坐标转换为三维立方体坐标
     * @param viewId 视图编号(0-5分别对应前、左、后、右、顶、底视图)
     * @param viewRow 视图中的行坐标
     * @param viewCol 视图中的列坐标
     * @param depth 视线深度(从近到远)
     * @param cubeX 输出的立方体X坐标
     * @param cubeY 输出的立方体Y坐标
     * @param cubeZ 输出的立方体Z坐标
     */
    void convertViewToCubeCoordinates(int viewId, int viewRow, int viewCol, int depth, 
                                     int& cubeX, int& cubeY, int& cubeZ) {
        switch(viewId) {
            case 0:  // 前视图 (front): 从 -Z 方向观察
                cubeX = viewRow;
                cubeY = viewCol;
                cubeZ = depth;
                break;
            case 1:  // 左视图 (left): 从 -X 方向观察
                cubeX = viewRow;
                cubeY = depth;
                cubeZ = cubeSize - viewCol - 1;
                break;
            case 2:  // 后视图 (back): 从 +Z 方向观察
                cubeX = viewRow;
                cubeY = cubeSize - viewCol - 1;
                cubeZ = cubeSize - depth - 1;
                break;
            case 3:  // 右视图 (right): 从 +X 方向观察
                cubeX = viewRow;
                cubeY = cubeSize - depth - 1;
                cubeZ = viewCol;
                break;
            case 4:  // 顶视图 (top): 从 +Y 方向观察
                cubeX = depth;
                cubeY = viewCol;
                cubeZ = cubeSize - viewRow - 1;
                break;
            case 5:  // 底视图 (bottom): 从 -Y 方向观察
                cubeX = cubeSize - depth - 1;
                cubeY = viewCol;
                cubeZ = viewRow;
                break;
        }
    }

public:
    /**
     * 初始化重构器,读取输入数据
     * @param size 立方体的尺寸 N
     */
    void initialize(int size) {
        cubeSize = size;
        
        // 读取6个方向的视图数据
        // 输入顺序:对于每一行,依次读取前、左、后、右、顶、底视图的对应行
        for (int row = 0; row < cubeSize; row++) {
            for (int viewId = 0; viewId < 6; viewId++) {
                for (int col = 0; col < cubeSize; col++) {
                    viewData[viewId][row][col] = readValidCharacter();
                }
            }
        }
        
        // 初始化立方体状态:'#' 表示立方体可能存在(初始状态)
        for (int x = 0; x < cubeSize; x++) {
            for (int y = 0; y < cubeSize; y++) {
                for (int z = 0; z < cubeSize; z++) {
                    cubeState[x][y][z] = '#';
                }
            }
        }
    }
    
    /**
     * 计算物体的最大可能重量
     * @return 最大重量(即存在的立方体数量)
     */
    int calculateMaximumWeight() {
        int cubeX, cubeY, cubeZ;  // 立方体坐标

        // 第一步:处理透明视图约束
        // 对于每个视图中标记为 '.' 的位置,移除整条视线上的所有立方体
        for (int viewId = 0; viewId < 6; viewId++) {
            for (int viewRow = 0; viewRow < cubeSize; viewRow++) {
                for (int viewCol = 0; viewCol < cubeSize; viewCol++) {
                    if (viewData[viewId][viewRow][viewCol] == '.') {
                        // 沿着视线方向,将所有立方体标记为不存在
                        for (int depth = 0; depth < cubeSize; depth++) {
                            convertViewToCubeCoordinates(viewId, viewRow, viewCol, depth, 
                                                        cubeX, cubeY, cubeZ);
                            cubeState[cubeX][cubeY][cubeZ] = '.';  // 标记为不存在
                        }
                    }
                }
            }
        }

        // 第二步:迭代处理颜色约束
        bool hasChanges;  // 标记本轮迭代是否有状态变化
        do {
            hasChanges = false;  // 初始假设没有变化
            
            // 遍历所有视图的所有颜色位置
            for (int viewId = 0; viewId < 6; viewId++) {
                for (int viewRow = 0; viewRow < cubeSize; viewRow++) {
                    for (int viewCol = 0; viewCol < cubeSize; viewCol++) {
                        char expectedColor = viewData[viewId][viewRow][viewCol];
                        // 只处理颜色位置,跳过透明位置
                        if (expectedColor != '.') {
                            // 沿着视线方向寻找第一个存在的立方体
                            for (int depth = 0; depth < cubeSize; depth++) {
                                convertViewToCubeCoordinates(viewId, viewRow, viewCol, depth,
                                                            cubeX, cubeY, cubeZ);
                                
                                // 如果当前立方体已确定不存在,继续检查下一个
                                if (cubeState[cubeX][cubeY][cubeZ] == '.') {
                                    continue;
                                }
                                
                                // 如果立方体颜色未确定,设置为期望颜色
                                if (cubeState[cubeX][cubeY][cubeZ] == '#') {
                                    cubeState[cubeX][cubeY][cubeZ] = expectedColor;
                                }
                                
                                // 如果颜色匹配,这个视图位置处理完成
                                if (cubeState[cubeX][cubeY][cubeZ] == expectedColor) {
                                    break;
                                }
                                
                                // 颜色冲突:立方体颜色与视图要求不符,必须移除
                                cubeState[cubeX][cubeY][cubeZ] = '.';
                                hasChanges = true;  // 标记有状态变化,需要继续迭代
                            }
                        }
                    }
                }
            }
        } while (hasChanges);  // 继续迭代直到没有状态变化

        // 统计最终存在的立方体数量
        int existingCubeCount = 0;
        for (int x = 0; x < cubeSize; x++) {
            for (int y = 0; y < cubeSize; y++) {
                for (int z = 0; z < cubeSize; z++) {
                    if (cubeState[x][y][z] != '.') {
                        existingCubeCount++;
                    }
                }
            }
        }
        
        return existingCubeCount;  // 每个立方体重1克,所以数量即为重量
    }
};

int main() {
    int cubeSize;
    CubeReconstructor reconstructor;
    
    // 处理多个测试用例,直到输入0为止
    while (scanf("%d", &cubeSize) == 1 && cubeSize != 0) {
        reconstructor.initialize(cubeSize);
        int maxWeight = reconstructor.calculateMaximumWeight();
        printf("Maximum weight: %d gram(s)\n", maxWeight);
    }
    
    return 0;
}

总结

本题通过迭代约束传播 的方法,从666个正交投影视图中重构三维物体。关键在于正确建立视图坐标与三维坐标的映射关系,以及通过多次迭代逐步确定或排除立方体的存在性。算法在保证正确性的同时,能够在合理时间内解决问题,体现了约束满足问题在实际应用中的巧妙解法。

相关推荐
AI柠檬2 小时前
几种排序算法的实现和性能比较
数据结构·算法·c#·排序算法
weixin_429630262 小时前
第6章 支持向量机
算法·机器学习·支持向量机
SweetCode2 小时前
C++ 实现大数加法
开发语言·c++·算法
王哈哈^_^2 小时前
【数据集】【YOLO】【目标检测】共享单车数据集,共享单车识别数据集 3596 张,YOLO自行车识别算法实战训推教程。
人工智能·算法·yolo·目标检测·计算机视觉·视觉检测·毕业设计
CodeWizard~3 小时前
AtCoder Beginner Contest 430赛后补题
c++·算法·图论
大大dxy大大3 小时前
机器学习-KNN算法示例
人工智能·算法·机器学习
关于不上作者榜就原神启动那件事4 小时前
模拟算法乒乓球
开发语言·c++·算法
Bug退退退1234 小时前
ArrayList 与 LinkedList 的区别
java·数据结构·算法
88号技师5 小时前
2025年7月一区SCI优化算法-Logistic-Gauss Circle optimizer-附Matlab免费代码
开发语言·算法·数学建模·matlab·优化算法