HDU 1864 最大报销额(01背包,烂题)
题意:被坑惨,单项不能超过600,其实是一张发票上A类/B类/C类的总和分别不能超过600。
思路:此题的数据很烂。用贪心也能过,用01背包也可以。都测试不出到底那些是错的。
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <stdlib.h> 5 #include <math.h> 6 #include <algorithm> 7 using namespace std; 8 const int N=31; //发票张数 9 double money; 10 int num,t; 11 int A,B,C; 12 double tick[N]; 13 14 int cmp(double a, double b) 15 { 16 return a>b?1:0; 17 } 18 void packet() 19 { 20 double ans=0; 21 sort(tick, tick+t, cmp); 22 for(int i=0; i<=t; i++) 23 { 24 if(money>=tick[i]) 25 { 26 ans+=tick[i]; 27 money-=tick[i]; 28 } 29 30 } 31 printf("%.2lf\n",ans); 32 33 } 34 35 36 int main() 37 { 38 freopen("input.txt","r",stdin); 39 40 int n,flag,u; 41 double cnt=0, pri; //只是用于计算每张发票总和 42 char c,tmp; 43 44 while(cin>>money>>num&&num) 45 { 46 t=0; 47 memset(tick, 0, sizeof(tick)); 48 49 for(int i=0; i<num; i++) //发票 50 { 51 flag=1;cnt=0;A=B=C=0; 52 53 cin>>n; 54 for(int j=0; j<n; j++) //发票项 55 { 56 cin>>c>>tmp>>pri; 57 cnt+=pri; 58 59 if(c=='A') 60 A+=pri; 61 else if(c=='B') 62 B+=pri; 63 else if(c=='C') 64 C+=pri; 65 else 66 flag=0; 67 } 68 if( !flag || cnt>1000 || A>600 || B>600 || C>600 ) 69 continue; 70 else 71 tick[t++]=cnt; 72 73 } 74 //以上都是输入的,重点在这个函数而已 75 packet(); 76 } 77 return 0; 78 }
我觉得贪心应该不能过的,比如有数据:
1001.5 4
1 A:500
1 C:400
1 A:300
1 B:200
贪心的结果是900,而正确答案是1000=500+300+200.。神奇的是AC了。
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <stdlib.h> 5 #include <math.h> 6 using namespace std; 7 const int N=31; //发票张数 8 double money; 9 double dp[30005]; 10 double tick[N]; 11 int num,t,A,B,C; 12 13 void packet() 14 { 15 for(int i=0; i<t; i++) 16 { 17 for(int j=ceil(money); ((double)j)-tick[i]>=money-floor(money); j--)//直接用向上取整来决定背包容量 18 { 19 double tmp = j-tick[i]; //还能放的容量 20 if( dp[int(ceil(tmp))] <= tmp && dp[int(ceil(tmp) )] + tick[i] <= money ) 21 tmp = dp[int(ceil(tmp) )] + tick[i]; 22 else 23 tmp = dp[int(tmp)] + tick[i]; 24 25 dp[j]= max( tmp , dp[j] ); 26 } 27 } 28 printf("%.2lf\n",dp[(int)ceil(money)]); 29 } 30 31 int main() 32 { 33 freopen("input.txt","r",stdin); 34 int n,flag,u; 35 double cnt=0, pri; //只是用于计算每张发票总和 36 char c,tmp; 37 38 while(cin>>money>>num&&num) 39 { 40 t=0; 41 memset(tick, 0, sizeof(tick)); 42 memset(dp, 0, sizeof(dp)); 43 44 for(int i=0; i<num; i++) //发票 45 { 46 flag=1;cnt=0;A=B=C=0; 47 cin>>n; 48 for(int j=0; j<n; j++) //发票项 49 { 50 cin>>c>>tmp>>pri; 51 cnt+=pri; 52 if(c=='A') 53 A+=pri; 54 else if(c=='B') 55 B+=pri; 56 else if(c=='C') 57 C+=pri; 58 else 59 flag=0; 60 } 61 if( !flag || cnt>1000 || A>600 || B>600 || C>600 ) 62 continue; 63 else 64 tick[t++]=cnt; 65 } 66 packet(); 67 } 68 return 0; 69 }
这个比上面的精确多了,至少上面的数据能测出正确答案。