http://acm.nyist.net/JudgeOnline/problem.php?pid=229
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN = 110;
int Ap[MAXN];
int Bp[MAXN];
int dp[MAXN];//dp[i]表示完成i个工作A,之后还能完成多少个工作B
int n,m;
int MAX(int a, int b)
{
return a > b ? a : b;
}
int slove( int mid )
{
int i,j,k;
memset(dp, -1, sizeof(dp));
for(i = 0; i <= m; ++i)//第一个人完成i个A,还可以完成多少个B
if(mid >= i*Ap[1])
dp[i] = (mid-i*Ap[1])/Bp[1];
else
break;
if(dp[m] >= m)//如果第一个人完成A之后,还有足够的时间来完成B,那么就说明这个mid时间是可以的
return 1;
//如果剩下的时间不足以完成B,或者给定mid的时间完不成A, 剩下的就是背包思想
for(i = 2; i <= n; ++i)
{//既然第一个人不能在给定的mid时间内完成两个任务,那么接下来在让其他人上,看前i是否可以完成任务
for(j = m; j >= 0; --j)
{
for(k = 0; k <= j && k*Ap[i] <= mid; ++k)
{//如果第i个人可以完成k份工作A,并且前i-1个人已完成了j-k个工作A,(即是否可以留更多的时间来做更多的工作)那么前i个工人还可以完成多少份工作?
if(dp[j-k] != -1)
dp[j] = MAX(dp[j], dp[j-k]+(mid-k*Ap[i])/Bp[i]);
}
}
if(dp[m] >= m)//如果前i(包括i)个工人完成A之后还能完成B,那么返回1,说明mid满足
return 1;
}
return 0;
}
int main()
{
int i,T;
scanf("%d", &T);
while(T--)
{
int maxtime = 0;
scanf("%d%d",&n,&m);
for(i = 1; i <= n; ++i)
{
scanf("%d%d",&Ap[i],&Bp[i]);
maxtime = MAX(maxtime, MAX(Ap[i], Bp[i]));
}
int L = 0,R = (maxtime*m) << 1;
while(L < R)
{
int mid = (L + R)>>1;
if(slove(mid))//如果给定的mid时间一直都满足,那么继续收缩区间,直到找到一个最小的时间
R = mid;
else
L = mid + 1;
}
printf("%d\n",L);
}
return 0;
}