题目大意:有N个箱子,M个求职者,每个求职者都有着其对应的能力P。每个箱子最多只能有一个人看管,求职者得到的工资为他所对应的能力值P,箱子的安全指数 = 看管它的人 / 这个人看管了几个箱子。最后取全部箱子安全系数值最小那个做为安全系数值,要求安全系数值达到最大,且分发的工资最少
解题思路:两次dp分别求出安全系数值,再求出工资,设dp[i][j]为从第i个到M-1个求职者看管j个箱子的安全系数的最大值,则dp[i][j] = max(dp[i][j],min(p[i]/k,DP(i+1,j-k))),p[i]是第i个求职者所对应的能力,k表示他看管的几个箱子
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
const int maxm = 30 + 5;
const int maxn = 100 + 5;
int L[maxm][maxn],Y[maxm][maxn],p[maxm],n,m;
int dp1(int i,int j) {
if(L[i][j] != -1)
return L[i][j];
if(j == 0)
return L[i][j] = INF;
if(i == m)
return L[i][j] = 0;
int k = min(j,p[i]);
for(; k >= 0; k--)
if(k)
L[i][j] = max(L[i][j],min(p[i]/k,dp1(i+1,j-k)));
else
L[i][j] = max(L[i][j],dp1(i+1,j));
return L[i][j];
}
int dp2(int i, int j) {
if(Y[i][j] != -1)
return Y[i][j];
if(j == 0)
return Y[i][j] = 0;
if(i == m)
return Y[i][j] = INF;
Y[i][j] = INF;
int k = min(p[i],j);
for(; k >= 0; k--)
if(k) {
if(L[0][n] <= min(p[i]/k,L[i+1][j-k]))
Y[i][j] = min(Y[i][j],p[i] + dp2(i+1,j-k));
}
else
if(L[0][n] <= L[i+1][j])
Y[i][j] = min(Y[i][j],dp2(i+1,j));
return Y[i][j];
}
int main() {
while(scanf("%d%d",&n,&m) != EOF && n + m) {
for(int i = 0;i < m; i++)
scanf("%d",&p[i]);
memset(L,-1,sizeof(L));
memset(Y,-1,sizeof(Y));
dp1(0,n);
dp2(0,n);
if(L[0][n] == 0)
printf("0 0\n");
else
printf("%d %d\n",L[0][n],Y[0][n]);
}
return 0;
}