先按做完题目的时间排序,在确定自己要做哪些题后,先做时间短的,这样能保证等的时间是最短的,在这里,能保证罚时会是最少的。然后0-1背包,0-1背包时先只管价值最大,在背包完后当价值一样时,再管题目做的多,题目数量一样时再管罚时少。
贴代码,代码中有注释:
View Code
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define INF 0x7fffffff//int类型中最大的正整数 5 using namespace std; 6 struct node1 7 { 8 int time,value;//时间,价值 9 bool operator < (const node1 & o)const 10 { 11 if(time < o.time) return true; 12 else return false; 13 } 14 } p[55]; 15 struct node2 16 { 17 int value,q,endtime,penalty;//价值,题目数量,结束时间,罚时 18 } f[1005];//f[i]中的i表示为时间限制为i 19 int main() 20 { 21 // freopen("in.cpp","r",stdin); 22 int r; 23 scanf("%d",&r); 24 while(r--) 25 { 26 int l,num; 27 scanf("%d%d",&l,&num); 28 for(int i=0; i<num; ++i) 29 scanf("%d",&p[i].time); 30 for(int i=0; i<num; ++i) 31 scanf("%d",&p[i].value); 32 sort(p,p+num);//排序 33 for(int i=0; i<=l; ++i)//0-1背包的恰好装满型 34 { 35 f[i].value = -INF;//初始值为负无穷 36 f[i].q = 0; 37 f[i].endtime= 0; 38 f[i].penalty = 0; 39 } 40 f[0].value = 0;//只有容量为0的初始值为0 41 for(int i=0; i<num; ++i) 42 { 43 for(int j=l; j >= p[i].time; --j) 44 { 45 int w =j-p[i].time; 46 if(f[w].value + p[i].value > f[j].value) 47 { 48 f[j].value = f[w].value + p[i].value; 49 f[j].q = f[w].q +1; 50 f[j].endtime = f[w].endtime + p[i].time;//该题的结束时间 51 //做到这个题的罚时=做到上题的罚时加上这题的结束时间 52 f[j].penalty = f[w].penalty + f[j].endtime; 53 } 54 } 55 } 56 node2 ans= {0,0,0}; 57 for(int i=0; i<=l; ++i) 58 { 59 if(f[i].value > ans.value)//价值最大优先 60 ans = f[i]; 61 else if(f[i].value == ans.value )//价值一样 62 { 63 if(f[i].q > ans.q)//做的题多的优先 64 ans = f[i]; 65 else if(f[i].q == ans.q && f[i].penalty < ans.penalty)//做的题数量一样后 66 //罚时少的优先 67 ans = f[i]; 68 } 69 } 70 printf("%d %d %d\n",ans.value,ans.q,ans.penalty);//输出结果 71 } 72 return 0; 73 }