剪草
题目大意:
有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]=min{f[i−1][j]+a[i].g+a[i].grow∗k不选f[i−1][j−1]+a[i].grow∗(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. 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 ) 不 选 选
注释:
不选的话就要加上他的高度,再生长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 ;
}