这还是以前在spoj上A的一道题,不过直接在poj提交时Time Limit Exceeded,本打算有时间把算法重新优化一下,昨天无聊把输入改为scanf试试,没想到竟然过了,意料之外。
简单的讲一下思路:
我们先考虑平面求面积的情况:
图1
图2
考虑与x轴平行的线段,沿y轴从下往上
1)出现重叠就删除重叠部分
2)出现相接部分就连接起来
例 图1
首先出现线段(0,0)-(10,0),长度l=10,往上遇到(0,3)-(3,3)、(7,3)-(10,3),相对高度h=3,此时面积增加 Δs=l*h=30;
按照原理1)此时线段变为(3,3)-(7,3), l=4
往上遇到(0,7)-(3,7)、(7,7)-(10,7),相对高度h=4,此时面积增加 Δs=l*h=16;
按照原理2)此时线段变为(0,7)-(10,7),l=10
往上遇到(0,10)-(10,10),相对高度h=3,此时面积增加 Δs=l*h=30;
按照原理1)此时线段变为(0,0)-(0,0),结束
所以总面积为30+16+30=76
同理 图2(点坐标与图1相同)
s=10*3+(3+3)*4+10*3=84
按照这样的思路,我们可以扩展到三维情况求体积
代码比较烂,也懒得改了,仅供有需要者测试用


#include<fstream>
#include <stdlib.h>
using namespace std;
struct ParallelXLine
{
int X1;
int X2;
int Y;
int Z;
}LineArray[20000], ZPlaneLine[10000], ZPlaneLineTemp[10000];
struct C2DLine{
int X1;
int X2;
}curLineArray[10000], nextLineArray[10000];
struct point{
int X;
int Y;
int Z;
}PArray[250];
int cmp(const void *a, const void *b)
{
struct ParallelXLine *c = (ParallelXLine *)a;
struct ParallelXLine *d = (ParallelXLine *)b;
if (c->Z != d->Z) return c->Z - d->Z;
if (c->Y != d->Y) return c->Y - d->Y;
if (c->X1 != d->X1) return c->X1 - d->X1;
else return c->X2 - d->X2;
}
int cmp2(const void *a, const void *b)
{
struct ParallelXLine *c = (ParallelXLine *)a;
struct ParallelXLine *d = (ParallelXLine *)b;
if (c->Y != d->Y) return c->Y - d->Y;
if (c->X1 != d->X1) return c->X1 - d->X1;
else return c->X2 - d->X2;
}
int main()
{
int T, F, P, L, Index, CurZ, CurY, ZPL, ZPLT, CLA, NLA, CurLength;
int area, vol;
scanf("%d",&T);
while (T--)
{
scanf("%d", &F);
//cin >> F;
L = 0;
while (F--)
{
area = vol = 0;
//cin >> P;
scanf("%d", &P);
bool isParallelToXY;
int pIndex;
for(pIndex = 0, isParallelToXY = true; pIndex < P; pIndex++)
{
scanf("%d%d%d",&PArray[pIndex].X, &PArray[pIndex].Y, &PArray[pIndex].Z);
if (pIndex > 0 && PArray[pIndex].Z != PArray[pIndex - 1].Z)
isParallelToXY = false;
}
if (isParallelToXY)
{
for (int i = 0; i < pIndex; i++)
{
if (i != 0 && PArray[i].Y == PArray[i- 1].Y)
{
LineArray[L].X1 = min(PArray[i].X, PArray[i - 1].X);
LineArray[L].X2 = max(PArray[i].X, PArray[i - 1].X);
LineArray[L].Y = PArray[i].Y;
LineArray[L].Z = PArray[i].Z;
L++;
}
if (i == P - 1 && PArray[i].Y == PArray[0].Y)
{
LineArray[L].X1 = min(PArray[i].X, PArray[0].X);
LineArray[L].X2 = max(PArray[i].X, PArray[0].X);
LineArray[L].Y = PArray[i].Y;
LineArray[L].Z = PArray[i].Z;
L++;
}
if (L > 1 && LineArray[L - 2].Y == LineArray[L - 1].Y && LineArray[L - 2].Z == LineArray[L - 1].Z)
{
if (LineArray[L - 2].X2 == LineArray [L - 1].X1)
{
LineArray[L - 2].X2 = LineArray[L - 1].X2;
L--;
}
else if (LineArray[L - 2].X1 == LineArray[L - 1].X2)
{
LineArray[L - 2].X1 = LineArray[L - 1].X1;
L--;
}
}
}
}
}
qsort(LineArray, L, sizeof(LineArray[0]), cmp);
Index = 0;
ZPL = 0;
while(Index < L)
{
if (T == 683 )
{
int aa = 0;
}
if (Index != 0)
vol += area * (LineArray[Index].Z - LineArray[Index - 1].Z);
CurZ = LineArray[Index].Z;
area = 0;
memcpy(ZPlaneLineTemp, ZPlaneLine, ZPL * sizeof(ZPlaneLine[0]));
ZPLT = ZPL;
while(Index < L && LineArray[Index].Z == CurZ)
{
for (CurY = LineArray[Index].Y; Index < L && LineArray[Index].Y == CurY && LineArray[Index].Z == CurZ; Index++)
{
if(ZPLT > 0 && LineArray[Index].X1 >= ZPlaneLineTemp[ZPLT - 1].X1
&& LineArray[Index].X1 <= ZPlaneLineTemp[ZPLT - 1].X2
&& LineArray[Index].Y == ZPlaneLineTemp[ZPLT - 1].Y
&& LineArray[Index].Z == ZPlaneLineTemp[ZPLT - 1].Z)
{
if (LineArray[Index].X1 > ZPlaneLineTemp[ZPLT - 1].X1 && LineArray[Index].X1 < ZPlaneLineTemp[ZPLT - 1].X2)
{
int minX2 = min(ZPlaneLineTemp[ZPLT - 1].X2, LineArray[Index].X2);
int maxX2 = max(ZPlaneLineTemp[ZPLT - 1].X2, LineArray[Index].X2);
ZPlaneLineTemp[ZPLT - 1].X2 = LineArray[Index].X1;
if (minX2 < maxX2)
{
ZPlaneLineTemp[ZPLT].X1 = minX2;
ZPlaneLineTemp[ZPLT].X2 = maxX2;
ZPlaneLineTemp[ZPLT].Y = CurY;
ZPlaneLineTemp[ZPLT].Z = CurZ;
ZPLT++;
}
}
else if (LineArray[Index].X1 == ZPlaneLineTemp[ZPLT - 1].X1)
{
int minX2 = min(ZPlaneLineTemp[ZPLT - 1].X2, LineArray[Index].X2);
int maxX2 = max(ZPlaneLineTemp[ZPLT - 1].X2, LineArray[Index].X2);
if (minX2 < maxX2)
{
ZPlaneLineTemp[ZPLT - 1].X1 = minX2;
ZPlaneLineTemp[ZPLT - 1].X2 = maxX2;
}
else
ZPLT--;
}
else
ZPlaneLineTemp[ZPLT - 1].X2 = LineArray[Index].X2;
}
else
{
ZPlaneLineTemp[ZPLT].X1 = LineArray[Index].X1;
ZPlaneLineTemp[ZPLT].X2 = LineArray[Index].X2;
ZPlaneLineTemp[ZPLT].Y = LineArray[Index].Y;
ZPlaneLineTemp[ZPLT].Z = LineArray[Index].Z;
ZPLT++;
}
}
}
qsort(ZPlaneLineTemp, ZPLT, sizeof(ZPlaneLineTemp[0]), cmp2);
ZPL = 0;
NLA = 0;
for (int i = 0; i < ZPLT;area += (CurLength * (ZPlaneLineTemp[i].Y - ZPlaneLineTemp[i - 1].Y)))
{
int split;
for (CurY = ZPlaneLineTemp[i].Y, split = ZPL; i < ZPLT && ZPlaneLineTemp[i].Y == CurY;)
{
if (i + 1 < ZPLT && ZPlaneLineTemp[i + 1].Y == CurY)
{
if (ZPlaneLineTemp[i].X1 == ZPlaneLineTemp[i + 1].X1)
{
if (ZPlaneLineTemp[i].X2 == ZPlaneLineTemp[i + 1].X2)
i+=2;
else
{
ZPlaneLineTemp[i+1].X1 = ZPlaneLineTemp[i].X2;
i++;
}
}
else if (ZPlaneLineTemp[i].X2 == ZPlaneLineTemp[i + 1].X1)
{
ZPlaneLineTemp[i + 1].X1 = ZPlaneLineTemp[i].X1;
i++;
}
else if (ZPlaneLineTemp[i+1].X1 > ZPlaneLineTemp[i].X1 && ZPlaneLineTemp[i + 1].X1 < ZPlaneLineTemp[i].X2)
{
ZPlaneLine[ZPL].X1 = ZPlaneLineTemp[i].X1;
ZPlaneLine[ZPL].X2 = ZPlaneLineTemp[i + 1].X1;
ZPlaneLine[ZPL].Y = CurY;
ZPlaneLine[ZPL].Z = ZPlaneLineTemp[i].Z;
ZPL++;
if (ZPlaneLineTemp[i].X2 == ZPlaneLineTemp[i + 1].X2)
i+=2;
else
{
ZPlaneLineTemp[i + 1].X1 = min(ZPlaneLineTemp[i + 1].X2, ZPlaneLineTemp[i].X2);
ZPlaneLineTemp[i + 1].X2 = max(ZPlaneLineTemp[i + 1].X2, ZPlaneLineTemp[i].X2);
i++;
}
}
else
{
ZPlaneLine[ZPL].X1 = ZPlaneLineTemp[i].X1;
ZPlaneLine[ZPL].X2 = ZPlaneLineTemp[i].X2;
ZPlaneLine[ZPL].Y = CurY;
ZPlaneLine[ZPL].Z = ZPlaneLineTemp[i].Z;
i++;
ZPL++;
}
}
else
{
ZPlaneLine[ZPL].X1 = ZPlaneLineTemp[i].X1;
ZPlaneLine[ZPL].X2 = ZPlaneLineTemp[i].X2;
ZPlaneLine[ZPL].Y = CurY;
ZPlaneLine[ZPL].Z = ZPlaneLineTemp[i].Z;
i++;
ZPL++;
}
}
int NLAIndex = 0;
CLA = 0;
CurLength = 0;
while (split < ZPL && NLAIndex < NLA)
{
if (ZPlaneLine[split].X1 == nextLineArray[NLAIndex].X1)
{
int minX2 = min(nextLineArray[NLAIndex].X2, ZPlaneLine[split].X2);
int maxX2 = max(nextLineArray[NLAIndex].X2, ZPlaneLine[split].X2);
if (minX2 == maxX2)
NLAIndex++;
else
{
nextLineArray[NLAIndex].X1 = minX2;
nextLineArray[NLAIndex].X2 = maxX2;
}
split++;
}
else if (ZPlaneLine[split].X2 == nextLineArray[NLAIndex].X1)
{
nextLineArray[NLAIndex].X1 = ZPlaneLine[split].X1;
split++;
}
else if (ZPlaneLine[split].X1 == nextLineArray[NLAIndex].X2)
{
nextLineArray[NLAIndex].X2 = ZPlaneLine[split].X2;
split++;
if (NLAIndex + 1 < NLA && nextLineArray[NLAIndex].X2 == nextLineArray[NLAIndex + 1].X1)
{
nextLineArray[NLAIndex + 1].X1 = nextLineArray[NLAIndex].X1;
NLAIndex++;
}
else
{
curLineArray[CLA].X1 = nextLineArray[NLAIndex].X1;
curLineArray[CLA].X2 = nextLineArray[NLAIndex].X2;
CurLength += (curLineArray[CLA].X2 - curLineArray[CLA].X1);
CLA++;
NLAIndex++;
}
}
else if (ZPlaneLine[split].X1 > nextLineArray[NLAIndex].X2)
{
curLineArray[CLA].X1 = nextLineArray[NLAIndex].X1;
curLineArray[CLA].X2 = nextLineArray[NLAIndex].X2;
CurLength += (curLineArray[CLA].X2 - curLineArray[CLA].X1);
NLAIndex++;
CLA++;
}
else if (nextLineArray[NLAIndex].X1 > ZPlaneLine[split].X2)
{
curLineArray[CLA].X1 = ZPlaneLine[split].X1;
curLineArray[CLA].X2 = ZPlaneLine[split].X2;
CurLength += (curLineArray[CLA].X2 - curLineArray[CLA].X1);
CLA++;
split++;
}
else
{
curLineArray[CLA].X1 = min(nextLineArray[NLAIndex].X1, ZPlaneLine[split].X1);
curLineArray[CLA].X2 = max(nextLineArray[NLAIndex].X1, ZPlaneLine[split].X1);
CurLength += (curLineArray[CLA].X2 - curLineArray[CLA].X1);
CLA++;
int minX2 = min(nextLineArray[NLAIndex].X2, ZPlaneLine[split].X2);
int maxX2 = max(nextLineArray[NLAIndex].X2, ZPlaneLine[split].X2);
if (minX2 == maxX2)
NLAIndex++;
else
{
nextLineArray[NLAIndex].X1 = minX2;
nextLineArray[NLAIndex].X2 = maxX2;
}
split++;
}
}
while (split < ZPL)
{
curLineArray[CLA].X1 = ZPlaneLine[split].X1;
curLineArray[CLA].X2 = ZPlaneLine[split].X2;
CurLength += (curLineArray[CLA].X2 - curLineArray[CLA].X1);
CLA++;
split++;
}
while (NLAIndex < NLA)
{
curLineArray[CLA].X1 = nextLineArray[NLAIndex].X1;
curLineArray[CLA].X2 = nextLineArray[NLAIndex].X2;
CurLength += (curLineArray[CLA].X2 - curLineArray[CLA].X1);
CLA++;
NLAIndex++;
}
memcpy(nextLineArray, curLineArray, CLA*sizeof(curLineArray[0]));
NLA = CLA;
}
}
printf("The bulk is composed of %d units.\n", vol);
}
return 0;
}