 /**//*
題意:給出n個(gè)人,第i個(gè)人完成任務(wù)A需要Ai時(shí)間,任務(wù)B需要Bi時(shí)間
問完成x個(gè)A,y個(gè)B任務(wù)所需的最少時(shí)間 并行工作
腦殘咯我,一開始就dp[i][j]=min(dp[i-1][j]+A[k],dp[i][j-1]+B[k])
能并行工作,上面式子當(dāng)然不行,上面時(shí)間被累加了

二分時(shí)間T,在這個(gè)時(shí)間下,dp[n][x]表示前面n個(gè)人完成x個(gè)A任務(wù)還能繼續(xù)完成的最大B任務(wù)數(shù)
然后背包就行了!

最后,發(fā)現(xiàn)這道題跟之前做的poj 1973一樣的
再次醉了

背包是累加的!
*/
#include<cstdio>
#include<cstring>

const int MAXN = 201;
const int INF = 1000000000;

int n,x,y;
int dp[MAXN];
int A[MAXN],B[MAXN];

 inline int min(int a,int b) {return a<b?a:b;}
 inline int max(int a,int b) {return a>b?a:b;}

bool chk(int T)
  {
memset(dp,-1,sizeof(dp));
dp[0]=0;
for(int i=1;i<=n;i++)
 {
int k = min(x,T/A[i]);
if(dp[x]>=y)return true;//很重要的優(yōu)化!!
for(int j=x;j>=0;j--)
for(int kk=0;kk<=k&&j-kk>=0;kk++)
 {
if(dp[j-kk]<0)continue;
dp[j]=max(dp[j],dp[j-kk]+(T-kk*A[i])/B[i]);
}
}
return dp[x]>=y;
}
int main()
  {
int T,t=1;
for(scanf("%d",&T);T--;)
 {
scanf("%d%d%d",&n,&x,&y);
for(int i=1;i<=n;i++)scanf("%d%d",&A[i],&B[i]);
int L=0,R=INF;
while(R-L>1)
 {
int M=(R+L)>>1;
if(chk(M))R=M;
else L=M;
}
printf("Case %d: %d\n",t++,R);
}
}
|