题解 P2589 【[ZJOI2006]碗的叠放】
先吐槽一下,我因为一些智障原因萎了很久
这是题目原图
我们首先需要知道指定两个碗叠放的状态,分情况讨论:
1、放在上方的碗底比下面的碗口还要大,那么多出来
2、原图左边的情况,上方的碗底与下方碗壁接触
3、原图右边上方的情况,下面的碗口与上面的碗壁相接
4、如果一个碗可以完全放入另一个碗里,且只有碗底平面相接,为
5、如果一个碗可以完全放入另一个碗里,但是里面的碗的碗口卡在了外面的碗壁上
有了这些关系之后,暴力dfs就可以得出答案
每次判断某个碗的高度时要与已经放入的 每个 碗测一下(因为有些碗放的时候是凹进去的,高度会比外面那只低)
上代码
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
#define dd c=getchar()
inline int read(){
int a=0,b=1,dd;
while(!isdigit(c)){if(c=='-')b=-b;dd;}
while(isdigit(c)){a=a*10+c-'0';dd;}
return a*b;
}
#undef dd
int n;
int h[10],r1[10],r2[10];
bool vis[10];
double ans,f[10][10],deep[10];
int tp=0;
void dfs(int p){
double x;
if(p>n){
x=0;
for(int i=1;i<=n;i++)if(deep[i]>x)x=deep[i];
ans=min(ans,x);
return;
}
tp++;
for(int i=1;i<=n;i++)if(!vis[i]){
x=0;
for(int j=1;j<=n;j++)if(vis[j])x=max(x,deep[j]+f[j][i]);
vis[i]=1;
deep[i]=x;
//for(int i=1;i<=tp;i++)putchar('\t');
//printf("%d %.6lf\n",i,x);
dfs(p+1);
vis[i]=0;
}
tp--;
}
int main(){
n=read();
for(int i=1;i<=n;i++){
h[i]=read();
r1[i]=read();
r2[i]=read();
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(r1[j]>=r2[i]){
f[i][j]=h[j];
continue;
}
f[i][j]=h[j]-h[i];
if(r1[j]>=r1[i]){
f[i][j]=max(f[i][j],h[j]-h[i]+h[i]*(double)(r1[j]-r1[i])/(double)(r2[i]-r1[i]));
}
if(r2[j]>=r2[i]){
f[i][j]=max(f[i][j],h[j]*(double)(r2[j]-r2[i])/(double)(r2[j]-r1[j]));
}else if(r2[j]>=r1[i]){
f[i][j]=max(f[i][j],h[i]*(double)(r2[j]-r1[i])/(double)(r2[i]-r1[i])-h[i]);
}
//printf("%d %d %.6lf\n",i,j,f[i][j]);
}
}
ans=1e9;
for(int i=1;i<=n;i++){
vis[i]=1;
deep[i]=h[i];
dfs(2);
vis[i]=0;
}
printf("%.0lf\n",ans);
return 0;
}