BZOJ 1859 Luogu P2589 [ZJOI2006]碗的叠放 (计算几何)

woc, 13年前的ZJOI就这么毒瘤的嘛。。。

题目链接: (bzoj)https://www.lydsy.com/JudgeOnline/problem.php?id=1859

(luogu)https://www.luogu.org/problemnew/show/P2589

题解: 大分类讨论,预处理\(ints[i][j]\)表示碗\(i\)叠在\(j\)上,\(i\)的底部比\(j\)的底部要高多少

然后分类讨论求此数组:

(1) \(i\)的下半径比\(j\)的上半径大,则等于\(j\)的高度

(2) \(i\)的上半径比\(j\)的下半径小,则等于零

(3) \(i\)的碗壁斜率大于\(j\)的碗壁斜率

(3.1) 若\(i\)的下半径小于等于\(j\)的下半径,则为零

(3.2) 若\(i\)的下半径大于\(j\)的下半径,则接触点横坐标为\(i\)的下半径,通过\(j\)的一次函数计算高度即可

(4) \(i\)的碗壁斜率小于\(j\)的碗壁斜率

(4.1) 若\(i\)的上半径大于等于\(j\)的上半径,则接触点为\(j\)的口处,通过\(i\)的一次函数计算高度

(4.2) 若\(i\)的上半径小于\(j\)的上半径,则(不妨先不考虑碗底)接触点横坐标为\(i\)的上半径,通过\(j\)的一次函数计算高度

情况(4)最后求出来的高度和\(0\)取Max.

(5) 若\(i\)\(j\)碗壁斜率相等

(5.1) 若\(i\)的下半径小于等于\(j\)的下半径,则高度为\(0\).

(5.2) 若\(i\)的下半径大于\(j\)的上半径,则接触点横坐标为\(i\)的下半径,通过一次函数计算高度即可。

然后一个显然的性质是一个碗叠在一摞碗上,它的叠放高度为和每个碗分别叠放的高度的Max.

这题……我还能说什么呢23333

代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<algorithm>
using namespace std;

const int N = 9;
struct Element
{
    int h,r1,r2;
    double calc(double x) {return h*(x-(double)r1)/((double)r2-r1);}
} a[N+3];
double hh[N+3];
int permu[N+3];
double ints[N+3][N+3];
int n;

double intersect(int x,int y)
{
//  printf("Intersect (%d,%d)\n",x,y);
    double ret;
    if(a[x].r1>a[y].r2) {ret = a[y].h;/* printf("Case 1\n");*/}
    else if(a[x].r2<a[y].r1) {ret = 0;/* printf("Case 2\n");*/}
    else if((a[y].r2-a[y].r1)*a[x].h>(a[x].r2-a[x].r1)*a[y].h)
    {
        if(a[x].r1<=a[y].r1) {ret = 0;/* printf("Case 3.1\n");*/}
        else {ret = a[y].calc((double)a[x].r1);/* printf("Case 3.2\n");*/}
    }
    else if((a[y].r2-a[y].r1)*a[x].h<(a[x].r2-a[x].r1)*a[y].h)
    {
        if(a[x].r2>=a[y].r2) {ret = a[y].h-a[x].calc(a[y].r2);/* printf("Case 4.1\n");*/}
//      else if(a[x].h*(a[y].r2-a[y].r1)<=a[y].h*(a[x].r2-a[y].r1)) {ret = 0;}
        else {ret = a[y].calc(a[x].r2)-a[x].calc(a[x].r2);/* printf("Case 4.2\n");*/}
        if(ret<0) ret = 0;
    }
    else
    {
        if(a[x].r1<=a[y].r1) {ret = 0;/* printf("Case 5.1\n");*/}
        else {ret = a[y].calc(a[x].r1);/* printf("Case 5.2\n");*/}
    }
//  printf("ret=%lf\n",ret);
    return ret;
}

double calc()
{
//  printf("calc: "); for(int i=1; i<=n; i++) printf("%d ",permu[i]); puts("");
    double ret = 0.0;
    for(int i=1; i<=n; i++)
    {
        hh[i] = 0;
        for(int j=1; j<i; j++)
        {
            hh[i] = max(hh[i],hh[j]+ints[permu[i]][permu[j]]);
        }
        ret = max(ret,hh[i]+a[permu[i]].h);
    }
//  printf("Total=%lf\n",ret); puts("");
    return ret;
}

int main()
{
    scanf("%d",&n);
    for(int i=1; i<=n; i++) scanf("%d%d%d",&a[i].h,&a[i].r1,&a[i].r2);
    for(int i=1; i<=n; i++) permu[i] = i;
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            if(i==j) continue;
            ints[i][j] = intersect(i,j);
        }
    }
    double ans = 1e6;
    do
    {
        ans = min(ans,calc());
    } while(next_permutation(permu+1,permu+n+1));

    printf("%d\n",(int)(ans+0.5));
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/suncongbo/p/11101670.html