算法训练 Balloons in a Box (枚举,模拟)

问题描述
  你要写一个程序,使得能够模拟在长方体的盒子里放置球形的气球。
  接下来是模拟的方案。假设你已知一个长方体的盒子和一个点集。每一个点代表一个可以放置气球的位置。在一个点上放置一个气球,就是以这个点为球心,然后让这个球膨胀,直到触及盒子的边缘或者一个之前已经被放置好的气球。你不能使用一个在盒子外面或者在一个之前已经放置好的气球里面的点。但是,你可以按你喜欢的任意顺序使用这些点,而且你不需要每个点都用。你的目标是按照某种顺序在盒子里放置气球,使得气球占据的总体积最大。
  你要做的是计算盒子里没被气球占据的体积。
输入格式
  第一行包含一个整数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
样例输出
774
数据规模和约定
  所有坐标的绝对值小于等于1000
  对于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;
}
View Code

 

posted @ 2018-02-07 21:06  Veritas_des_Liberty  阅读(1654)  评论(0编辑  收藏  举报