Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 521 Accepted Submission(s): 243
说实话本题如果让我自己想,我肯定想不到会是这样做,本体的思想就是二分+DP,二分就是对时间进行二分处理,然后判断在这个时间段内能否完成所给的任务;dp用的是一个二维数组 f[i][k]表示前i个人完成K件A任务时,最多完成多少件B任务,当前i个人完成x件A任务时还能完成Y件B任务时,表示可行返回true
代码:
1 #include<stdio.h>
2 #include<string.h>
3 int a[55],b[55],n,x,y,f[55][205];
4 int min(int x,int y)
5 {
6 if(x<y)
7 return x;
8 return y;
9 }
10 int dp(int t)
11 {
12 int i,j,k;
13 memset(f,-1,sizeof(f));
14 f[0][0]=0;
15 for(i=1;i<=n;i++) //总共有N个人,求前i个人做j个A任务时最多能够做多少B任务
16 {
17 if(f[i][x]>=y) //如果能够完成返回1
18 return 1;
19 for(j=0;j<=x;j++) //总共有x件A任务
20 {
21 if(f[i-1][j]!=-1) //表示可以进行DP
22 {
23 int temp=min(t/a[i],x-j); //对第i个人可以做的多少件A任务进行枚举,前N个人做的A任务不能超过X
24 for(k=0;k<=temp;k++)
25 {
26 int t1=(t-a[i]*k)/b[i]; //当第i个人作K件A任务时,最多可以做t1件B任务
27 if(f[i][j+k]<f[i-1][j]+t1) //保存最大的
28 f[i][j+k]=f[i-1][j]+t1;
29 }
30 }
31 }
32 }
33 if(f[n][x]>=y) //如果能够完成返回1
34 return 1;
35 return 0;
36 }
37
38 int main()
39 {
40 int t,count=0,i,ans,l,r,mid;
41 scanf("%d",&t);
42 while(t--)
43 {
44 count++;
45 scanf("%d%d%d",&n,&x,&y);
46 for(i=1;i<=n;i++)
47 scanf("%d%d",&a[i],&b[i]);
48 l=0;r=a[1]*x+b[1]*y;
49 while(l<=r) //对时间进行二分
50 {
51 mid=(l+r)>>1;
52 if(dp(mid))
53 {
54 ans=mid; //因为题意是求最小的时间所以当成功时继续往下查找
55 r=mid-1;
56 }
57 else
58 l=mid+1;
59 }
60 printf("Case %d: %d\n",count,ans);
61 }
62 return 0;
63 }
64
65
66
67
68