1 条题解

  • 0
    @ 2025-4-10 12:41:23

    解题思路

    面的解析: 每个面由多个点组成,这些点位于一个正交平面上(即所有点的某一坐标相同)。 通过解析这些面,可以确定Bulk的边界范围。

    离散化坐标: 将所有面的坐标点进行离散化处理,得到所有可能的X、Y、Z坐标值,并排序去重。这样可以将连续的坐标空间划分为离散的区间,便于后续处理。

    扫描线算法: 使用扫描线算法(类似于计算三维物体的体积)来遍历离散化后的坐标空间。对于每个离散化的区间(即单位立方体的可能位置),检查其是否被包含在Bulk的内部。

    判断立方体是否在内部: 对于每个单位立方体,检查其在各个方向上是否被面包围。可以通过射线法或其他几何方法判断点是否在面内。

    计算体积: 统计所有被判定为内部的单位立方体的数量,即为Bulk的体积。

    代码实现

    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    #define MAX_SURFACES 1000
    #define MAX_EDGES 1000
    int Compare(const void *e1, const void *e2);
    bool SurfaceHit(int index, int innerx, int innery);
    int FindSurface(int innerx, int innery, int startindex);
    void DoIt();
    
    struct Edge {
        int X, Y;
    };
    
    struct Surface {
        bool Clockwise;
        int Area;
        int InnerX, InnerY;
        int EdgeCount;
        bool TopInner;
        Edge Edges[MAX_EDGES];
    };
    
    struct SurfaceIndex {
        int Level;
        int Index;
        bool operator<(const SurfaceIndex& other) const {
            if (Level == other.Level) 
                return Index < other.Index;
            return Level < other.Level;
        }
    };
    
    SurfaceIndex SurfaceIndexes[MAX_SURFACES];
    Surface Surfaces[MAX_SURFACES];
    int SurfaceCount;
    
    int Compare(const void *e1, const void *e2)
    {
        const struct SurfaceIndex *si1 = (struct SurfaceIndex*)e1;
        const struct SurfaceIndex *si2 = (struct SurfaceIndex*)e2;
        if (si1->Level == si2->Level)
            return si1->Index < si2->Index  ? -1 : 1;
        return si1->Level < si2->Level ? -1 : 1;
    }
    
    bool SurfaceHit(int index, int innerx, int innery)
    {
        int i;
        int maxy = -2000000000;
        bool result = false;
        
        for (i=0; i<Surfaces[index].EdgeCount; i++)
        {
            int last = (i == Surfaces[index].EdgeCount-1) ? 0 : i+1;
            int minx, maxx, y;
            if (Surfaces[index].Edges[i].X ==
                Surfaces[index].Edges[last].X) continue;
            y = Surfaces[index].Edges[i].Y;
            minx = min(Surfaces[index].Edges[i].X, Surfaces[index].Edges[last].X);
            maxx = max(Surfaces[index].Edges[i].X, Surfaces[index].Edges[last].X);
            if (innery < y || y < maxy || innerx < minx || innerx >= maxx)
                continue;
            result = (Surfaces[index].Edges[i].X < Surfaces[index].Edges[last].X)
            ^ Surfaces[index].Clockwise;
            maxy = y;
        }
        return result;
    }
    
    int FindSurface(int innerx, int innery, int startindex)
    {
        int i;
        int level = SurfaceIndexes[startindex].Level;
        
        for (i=startindex; i>=0 && SurfaceIndexes[i].Level == level; i--);
    
        for (; i>=0; i--)
        {
            int index = SurfaceIndexes[i].Index;
            if (SurfaceHit(index, innerx, innery)) return index;
        }
        return -1;
    }
    
    void DoIt()
    {
        int i, j, surfaces, edges;
        int deltax, deltay, x, y;
        int level, volume;
        bool skip;
        
        cin >> surfaces;
        SurfaceCount = 0;
        for (i=0; i<surfaces; i++)
        {
            cin >> edges;
            
            skip = false;
            for (j=0; j<edges; j++)
            {
                cin >> Surfaces[SurfaceCount].Edges[j].Y
                    >> Surfaces[SurfaceCount].Edges[j].X
                    >> level;
                
                if (j == 0)
                    SurfaceIndexes[SurfaceCount].Level = level;
                else
                    if (level != SurfaceIndexes[SurfaceCount].Level)
                        skip = true;
            }
            
            if (skip) continue;
            
            Surfaces[SurfaceCount].EdgeCount = edges;
            SurfaceIndexes[SurfaceCount].Index = SurfaceCount;
    
            Surfaces[SurfaceCount].Area = 0;
            for (j=0; j<edges; j++)
            {
                int last = (j == edges-1) ? 0 : j+1;
                if (Surfaces[SurfaceCount].Edges[j].X ==
                    Surfaces[SurfaceCount].Edges[last].X) continue;
                Surfaces[SurfaceCount].Area +=
                Surfaces[SurfaceCount].Edges[j].Y *
                (Surfaces[SurfaceCount].Edges[last].X - 
                    Surfaces[SurfaceCount].Edges[j].X);
            }
            if (Surfaces[SurfaceCount].Area > 0)
                Surfaces[SurfaceCount].Clockwise = true;
            else
            {
                Surfaces[SurfaceCount].Clockwise = false;
                Surfaces[SurfaceCount].Area = -Surfaces[SurfaceCount].Area;
            }
    
            x = Surfaces[SurfaceCount].Edges[0].X;
            deltax = Surfaces[SurfaceCount].Edges[1].X - x;
            y = Surfaces[SurfaceCount].Edges[0].Y;
            deltay = Surfaces[SurfaceCount].Edges[1].Y - y;
            Surfaces[SurfaceCount].InnerX = x;
            Surfaces[SurfaceCount].InnerY = y;
            if (Surfaces[SurfaceCount].Clockwise)
            {
                if (deltay < 0)
                {
                    Surfaces[SurfaceCount].InnerX--;
                    Surfaces[SurfaceCount].InnerY--;
                }
                else
                    if (deltax < 0)
                        Surfaces[SurfaceCount].InnerX--;
                else
                    if (deltax > 0)
                        Surfaces[SurfaceCount].InnerY--;
            }
            else
            {
                if (deltax < 0)
                {
                    Surfaces[SurfaceCount].InnerX--;
                    Surfaces[SurfaceCount].InnerY--;
                }
                else
                    if (deltay > 0)
                        Surfaces[SurfaceCount].InnerX--;
                else
                    if (deltay < 0)
                        Surfaces[SurfaceCount].InnerY--;
            }
            
            SurfaceCount++;
            
        }
        sort(SurfaceIndexes, SurfaceIndexes + SurfaceCount);
        for (i=0; i<SurfaceCount; i++)
        {
            int index = SurfaceIndexes[i].Index;
            int hit = FindSurface(Surfaces[index].InnerX,
                Surfaces[index].InnerY, i);
            if (hit == -1)
                Surfaces[index].TopInner = true;
            else
                Surfaces[index].TopInner = !Surfaces[hit].TopInner;
        }
        
        volume = 0;
        for (i=0; i<SurfaceCount; i++)
        {
            int index = SurfaceIndexes[i].Index;
            if (Surfaces[index].TopInner)
                volume -= Surfaces[index].Area * SurfaceIndexes[i].Level;
            else
                volume += Surfaces[index].Area * SurfaceIndexes[i].Level;
        }
        cout << "The bulk is composed of " << volume << " units." << endl;
    }
    
    int main()
    {
        int i, n;
        cin >> n;
        
        for (i=0; i<n; i++)
            DoIt();
        
        return 0;
    }
    
    • 1

    信息

    ID
    398
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    3
    已通过
    1
    上传者