【DP】剪草(jzoj 1510)

版权声明:欢迎借鉴,谢绝抄搬。 https://blog.csdn.net/ssllyf/article/details/86695744

剪草

题目大意:

有n棵小草,B某看它们很不顺眼,想让他们的高度总和不大于H,它们一开始各有一个高度,然后它们各有一个固定的生长值,B某每个单位时间可以将一棵草减掉(让他的高度变为0),但小草每个单位时间会长一次,问B某在哪个时间可以让小草总高度不大于H,如果永远不可能,那就输出-1

数据范围限制

1 ≤ N ≤ 50,0 ≤ H ≤ 1000000

0 ≤ h[i] ≤ 100000

1 ≤ grow[i] ≤ 100000

对于20%的数据, 1 ≤ N ≤ 7。

提示

在这里插入图片描述

解题思路:

我们可以用f[i][j]来表示前i棵草减j次的最小高度,然后先枚举结束时间(k),再枚举第几棵小草(i),再枚举当前时间(j),就得出下图的公式,再套进去算一下就可以了

f [ i ] [ j ] = m i n { f [ i 1 ] [ j ] + a [ i ] . g + a [ i ] . g r o w k f [ i 1 ] [ j 1 ] + a [ i ] . g r o w ( k j ) f[i][j]=min\left\{\begin{matrix}f[i-1][j]+a[i].g+a[i].grow*k &不选\\ f[i-1][j-1]+a[i].grow*(k-j)&选\end{matrix}\right.

注释:

不选的话就要加上他的高度,再生长k次,选的话就不加高度,但要算出接下来要生长的高度(k-j)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int ans,n,h,f[55][55];
struct rec
{
	int grow,g;
}a[55];
bool cmp(rec x,rec y)
{
	return x.grow<y.grow;
}
int main()
{
	ans=-1;
	scanf("%d %d",&n,&h);
	for (int i=1;i<=n;++i)
	  scanf("%d",&a[i].g);//输入
	for (int i=1;i<=n;++i)
	  scanf("%d",&a[i].grow);//输入
	sort(a+1,a+1+n,cmp);//按生长速度从小到大排序
	for (int k=0;k<=n;++k)
	  {
	  	for (int i=1;i<=n;++i)
	  	  for (int j=1;j<=i;++j)
	  	    f[i][j]=2147483647;//预处理
	  	for (int i=1;i<=n;++i) f[i][0]=f[i-1][0]+a[i].g+a[i].grow*k;//处值
	  	for (int i=1;i<=n;++i)
	  	  for (int j=1;j<=k;++j)
	  	    f[i][j]=min(f[i-1][j]+a[i].g+a[i].grow*k,f[i-1][j-1]+a[i].grow*(k-j));//状态转移方程
	  	if (f[n][k]<=h)//判断是否成立
	  	{
	  		ans=k;
	  		break;
		}
	  }
	printf("%d",ans);//输出
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ssllyf/article/details/86695744