SSL1371 鱼肉炸弹【树形DP】【伪二分】

SSL1371 鱼肉炸弹【树形DP】【伪二分】_第1张图片

题目大意:

有很多楼,每个楼有一个高度 Hi 和一个猫数 Ci i i i 楼比 j j j 楼高时, j j j 楼的值就会加上 i i i 楼的值,让我们去掉一些楼,使剩下的楼的值中最大值是所有方案里最小的。

思路:

首先我们考虑建树,以当前高度最高的点为根节点,它左边是左子树,右边是右子树。
当然,最高的为根。

long long get(long long l,long long r)
{
	if(l>r) return 0;
	if(l==r) return r;
	long long ans=0,mid=0;
	for(long long i=l; i<=r; i++)
	 {
	 	if(h[i]>ans)
	 	 {
	 	 	ans=h[i];
	 	 	mid=i;
	 	 }
	 }
	a[mid].l=get(l,mid-1);
	a[mid].r=get(mid+1,r);
	return mid;
}

然后我们考虑怎样DP,我们可以设 f [ x ] [ i + j ] f[x][i+j] f[x][i+j] 为当前 x x x 号节点,给左子树 i i i 个炸弹,给右子树 j j j 个炸弹所获得的最小值; f [ x ] [ i + j + 1 ] f[x][i+j+1] f[x][i+j+1] 为当前 x x x 号节点,给左子树 i i i 个炸弹,给右子树 j j j 个炸弹,自己给一个炸弹所获得的最小值;
可得动态转移方程:
f [ x ] [ i + j ] = m i n ( f [ x ] [ i + j ] , m a x ( f [ a [ x ] . l ] [ i ] , f [ a [ x ] . r ] [ j ] ) + c [ x ] ) ; f[x][i+j]=min(f[x][i+j],max(f[a[x].l][i],f[a[x].r][j])+c[x]); f[x][i+j]=min(f[x][i+j],max(f[a[x].l][i],f[a[x].r][j])+c[x]);
i f ( i + j < k ) if(i+jif(i+j<k)
f [ x ] [ i + j + 1 ] = m i n ( f [ x ] [ i + j + 1 ] , m a x ( f [ a [ x ] . l ] [ i ] , f [ a [ x ] . r ] [ j ] ) ) ; f[x][i+j+1]=min(f[x][i+j+1],max(f[a[x].l][i],f[a[x].r][j])); f[x][i+j+1]=min(f[x][i+j+1],max(f[a[x].l][i],f[a[x].r][j]));

代码

#include
#include
#include
#include
#include
using namespace std;
long long n,k,root,h[100010],c[100010],f[201000][10]; 
long long v[100010];
struct node
{
	long long l,r;
}a[100010];
long long get(long long l,long long r)
{
	if(l>r) return 0;
	if(l==r) return r;
	long long ans=0,mid=0;
	for(long long i=l; i<=r; i++)
	 {
	 	if(h[i]>ans)
	 	 {
	 	 	ans=h[i];
	 	 	mid=i;
	 	 }
	 }
	a[mid].l=get(l,mid-1);
	a[mid].r=get(mid+1,r);
	return mid;
}
void dfs(long long x)
{
	v[x]=1;
	if(!v[a[x].l])
	  dfs(a[x].l);
	if(!v[a[x].r])
	  dfs(a[x].r);
	for(long long i=0; i<=k; i++)
	 for(long long j=0; j<=k-i; j++)
	  {
	  	 f[x][i+j]=min(f[x][i+j],max(f[a[x].l][i],f[a[x].r][j])+c[x]);
	  	 if(i+j<k)
	  	   f[x][i+j+1]=min(f[x][i+j+1],max(f[a[x].l][i],f[a[x].r][j]));
	  }
}
int main()
{
	memset(f,0x3f,sizeof(f)); 
	f[0][0]=0;
    cin>>n>>k;
    for(long long i=1; i<=n; i++)
       scanf("%lld%lld",&h[i],&c[i]);
    root=get(1,n);
    dfs(root);
    cout<<f[root][k];
    return 0;
}

你可能感兴趣的:(题解,dp,二分)