問題描述
你要寫一個程序,使得能夠模擬在長方體的盒子里放置球形的氣球。
接下來是模擬的方案。假設你已知一個長方體的盒子和一個點集。每一個點代表一個可以放置氣球的位置。在一個點上放置一個氣球,就是以這個點為球心,然后讓這個球膨脹,直到觸及盒子的邊緣或者一個之前已經被放置好的氣球。你不能使用一個在盒子外面或者在一個之前已經放置好的氣球里面的點。但是,你可以按你喜歡的任意順序使用這些點,而且你不需要每個點都用。你的目標是按照某種順序在盒子里放置氣球,使得氣球占據的總體積最大。
你要做的是計算盒子里沒被氣球占據的體積。
接下來是模擬的方案。假設你已知一個長方體的盒子和一個點集。每一個點代表一個可以放置氣球的位置。在一個點上放置一個氣球,就是以這個點為球心,然后讓這個球膨脹,直到觸及盒子的邊緣或者一個之前已經被放置好的氣球。你不能使用一個在盒子外面或者在一個之前已經放置好的氣球里面的點。但是,你可以按你喜歡的任意順序使用這些點,而且你不需要每個點都用。你的目標是按照某種順序在盒子里放置氣球,使得氣球占據的總體積最大。
你要做的是計算盒子里沒被氣球占據的體積。
輸入格式
第一行包含一個整數n表示集合里點的個數(1≤n≤6)。第二行包含三個整數表示盒子的一個角落的(x,y,z)坐標,第三行包含與之相對的那個角落的(x,y,z)坐標。接下來n行,每行包含三個整數,表示集合中每個點的(x,y,z)坐標。這個盒子的每維的長度都是非零的,而且它的邊與坐標軸平行。
輸出格式
只有一行,為那個盒子沒被氣球占據的最小體積(四舍五入到整數)。
樣例輸入
2
0 0 0
10 10 10
3 3 3
7 7 7
0 0 0
10 10 10
3 3 3
7 7 7
樣例輸出
774
數據規模和約定
所有坐標的絕對值小於等於1000
對於20%的數據:n=1
對於50%的數據:1≤n≤3
對於100%的數據:1≤n≤6
對於20%的數據:n=1
對於50%的數據:1≤n≤3
對於100%的數據:1≤n≤6
這道題主要學習了幾何模擬方面的知識
另外還學習了STL庫中的next-permutation函數
這個函數主要是求全排列用的
#include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; const int maxn = 10; const double inf = 0x7ffffff; const double pi = acos(-1.0); struct point { double x,y,z; double r; }a[maxn], s, e; //s和e是關於長方體的兩個對點,a[]是關於長方體內的氣球的位置 int n; double ans; double dis(point p1, point p2) { double tmp1 = (p1.x - p2.x)*(p1.x - p2.x); double tmp2 = (p1.y - p2.y)*(p1.y - p2.y); double tmp3 = (p1.z - p2.z)*(p1.z - p2.z); return sqrt(tmp1+tmp2+tmp3); } double solve(int i) //球心位置到長方體側面的最短距離 { double t1 = min(fabs(a[i].x - e.x), fabs(a[i].x - s.x)); double t2 = min(fabs(a[i].y - e.y), fabs(a[i].y - s.y)); double t3 = min(fabs(a[i].z - e.z), fabs(a[i].z - s.z)); double r = min(t1, t2); r = min(r, t3); return r; } double area(double r) //求的面積 { return 4.0*r*r*r*pi/3.0; } int main() { while(~scanf("%d", &n)) { scanf("%lf %lf %lf", &s.x, &s.y, &s.z); scanf("%lf %lf %lf", &e.x, &e.y, &e.z); double total = fabs((s.x - e.x)*(s.y - e.y)*(s.z - e.z)); memset(a, 0, sizeof(a)); for(int i = 0; i < n; i++) scanf("%lf %lf %lf", &a[i].x, &a[i].y, &a[i].z); double ans = 0; int vis[maxn]; for(int i = 0; i < n; i++) vis[i] = i; do { for(int i = 0; i < n; i++) a[i].r = 0; double tmp = 0; for(int i = 0; i < n; i++) { a[vis[i]].r = solve(vis[i]); for(int j = 0; j < n; j++) { if(i == j || a[vis[j]].r == 0) continue; double tt = dis(a[vis[j]], a[vis[i]]) - a[vis[j]].r; tt = max(tt, 0.0); a[vis[i]].r = min(a[vis[i]].r, tt); } tmp += area(a[vis[i]].r); } ans = max(ans, tmp); }while(next_permutation(vis, vis+n)); //求出關於各個圓心位置的全排列 printf("%.0f\n", fabs(total-ans)); //關於next_permutation:http://bbs.csdn.net/topics/392058688 } return 0; }
