比较水,需要先做一些预处理。为了让卡里最终的钱最少,我们肯定会在条件允许的情况下(卡里的余额大于五)最后买最贵的菜,这样,我们先把初始余额减5,然后把最贵的菜挑出去,考虑用初始余额减5的钱买剩下的菜,使最终余额>0且最少,然后再把这个余额减最贵的菜钱就是答案。
状态转移方程 dp[ i ][ j ] = min( dp[ i-1 ][ j ], dp[ i-1 ][ j-a[ i ] ]-a[ i ] )
其中dp[ i ][ j ]代表第i个菜时卡里有j钱的余额。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
using namespace std;
int a[1005];
int n, sum;
int dp[1005][1100];
int INF = 1000000;
int main()
{
//freopen("ztest.txt","r",stdin);
while(scanf("%d", &n) && n)
{
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
sort(a+1, a+1+n);
int maxd = a[n];
scanf("%d",&sum);
sum = sum-5;
if(sum >= 0)
{
for(int i = 0; i <= n; i++)
for(int j = 0; j <= sum; j++)
dp[i][j] = INF;
for(int i = 0; i <= sum; i++)
dp[0][i] = sum;
for(int i = 1; i <= n - 1; i++)
for(int j = 0; j <= sum; j++)
{
dp[i][j] = dp[i-1][j];
if(j >= a[i])
dp[i][j] = min(dp[i-1][j], dp[i-1][j-a[i]]-a[i]);
}
printf("%d\n",dp[n-1][sum]-maxd+5);
}
else
printf("%d\n",sum+5);
}
return 0;
}