首先我们要证明一个结论,也就是任何时刻雇佣的人数一定是所有月份中要求最小人数中的一个,因为对于每个人来说,如果一个人被开除会获得更高利润,那么多余的人都开除掉才能获得最大的利润,当前雇佣也一定是雇佣到正好和自己最少人数相等时才会获得最大收益
那么dp[i][j],在第i个月持有第j个月的最小人数
具体转移代码中很清楚.
下面是ac代码:
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #define MAX 15 using namespace std; typedef long long LL; LL dp[MAX][MAX]; LL a[MAX]; LL maxn; LL n,h,s,f; int main ( ) { while ( ~scanf ( "%lld" , &n ) , n ) { scanf ( "%lld%lld%lld" , &h , &s , &f ); for ( int i = 1 ; i <= n ; i++ ) scanf ( "%lld" , &a[i] ); memset ( dp , 0x3f , sizeof ( dp ) ); LL ans = dp[1][1]; dp[1][1] = a[1]*(s+h); for ( int i = 2 ; i <= n ; i++ ) { for ( int j = 1 ; j <= n ; j++ ) for ( int k = 1 ; k <= n ; k++ ) if ( a[i] <= a[j] && a[i-1] <= a[k] ) { LL temp= a[j]*s + dp[i-1][k]; if ( a[j] > a[k] ) temp += h*(a[j]-a[k]); if ( a[j] < a[k] ) temp += f*(a[k]-a[j]); dp[i][j] = min ( dp[i][j] , temp ); } } for ( int i = 1 ; i <= n ; i++ ) ans = min ( ans , dp[n][i] ); printf ( "%lld\n" , ans ); } }