方法一、d[i][j][k]表示前i个人看j个货总保险值为k时的最小花费。时间复杂度较高。
//10163 Storage Keepers Accepted C++ 0.236 2012-12-14 03:23:11
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 100+5, MAXM = 30+5, MAXP = 1000+5;
const int INF = 0x3f3f3f3f;
int N, M, P[MAXM];
int d[MAXM][MAXN][MAXP];
int main()
{
while (scanf("%d%d", &N, &M))
{
if (!N && !M)
break;
for (int i = 1; i <= M; i++)
scanf("%d", &P[i]);
for (int i = 0; i <= M; i++)
for (int j = 0; j <= N; j++)
for (int k = 1; k <= 1000; k++)
d[i][j][k] = INF;
for (int i = 0; i < M; i++)
for (int j = 0; j <= N; j++)
for (int k = 0; k <= 1000; k++) if (d[i][j][k] < INF)
{
d[i+1][j][k] = min(d[i+1][j][k], d[i][j][k]);
for (int l = 1; j+l <= N; l++)
{
if (j)
d[i+1][j+l][min(k, P[i+1]/l)] = min(d[i+1][j+l][min(k, P[i+1]/l)], d[i][j][k]+P[i+1]);
else
d[i+1][j+l][P[i+1]/l]= min(d[i+1][j+l][P[i+1]/l], d[i][j][k]+P[i+1]);
}
}
for (int k = 1000; k >= 0; k--)
if (d[M][N][k] < INF)
{
printf("%d %d\n", k, d[M][N][k]);
break;
}
}
return 0;
}
方法二、d[i][j]表示前i个人看j个货时最大的总保险值,f[i][j]表示前i个人看j个货并达到最大的总保险值时的最小花费。
//10163 Storage Keepers Accepted C++ 0.012 2012-12-14 03:21:21
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 100+5, MAXM = 30+5, MAXP = 1000+5;
const int INF = 0x3f3f3f3f;
int N, M, P[MAXM];
int d[MAXM][MAXN], f[MAXM][MAXN];
int main()
{
for (int i = 0; i <= 30; i++)
d[i][0] = INF;
while (scanf("%d%d", &N, &M))
{
if (!N && !M)
break;
for (int i = 1; i <= M; i++)
scanf("%d", &P[i]);
for (int i = 1; i <= M; i++)
for (int j = 1; j <= N; j++)
{
d[i][j] = d[i-1][j];
for (int k = 1; k <= j; k++)
d[i][j] = max(d[i][j], min(d[i-1][j-k], P[i]/k));
}
for (int i = 0; i <= M; i++)
for (int j = 1; j <= N; j++)
f[i][j] = INF;
for (int i = 1; i <= M; i++)
for (int j = 1; j <= N; j++)
{
f[i][j] = f[i-1][j];
for (int k = 1; k <= j; k++)
if (P[i]/k >= d[M][N])
f[i][j] = min(f[i][j], f[i-1][j-k]+P[i]);
}
printf("%d %d\n", d[M][N], d[M][N] ? f[M][N] : 0);
}
return 0;
}