版权声明:欢迎借鉴,谢绝抄搬。 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),就得出下图的公式,再套进去算一下就可以了
注释:
不选的话就要加上他的高度,再生长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;
}