给出n(n<=1000)个考试的成绩ai和满分bi,要求去掉k个考试成绩,使得剩下的∑ai/∑bi*100最大并输出。
典型的01分数规划
要使∑ai/∑bi最大,不妨设ans=∑ai/∑bi,则∑ai-ans*∑bi=0。
设f[ans]=∑ai-ans*∑bi,我们要求一个ans的最大值,使得存在一组解,满足f[ans]=0,而其他的任意解都有f[ans]<=0(如果f[ans]>0,说明∑ai/∑bi>ans,即还有比ans更优的解),对于∑ai/∑bi,从0~1二分枚举答案,对于每一个枚举到的答案mid,如果f[mid]的最大值>0,则说明存在更大的ans,从mid~r里边进一步找更优的解。否则从l~mid中找。
如何求f[mid]的最大值,f[ans]=∑ai-ans*∑bi=∑(ai-ans*bi)
显然如果mid确定了,那么对于每个考试,ai-mid*bi的值也就确定,那么从大到小排序,取最大的n-m个数进行累加即可。
二分答案法 94MS
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<iostream> 5 #include<algorithm> 6 #include<set> 7 #include<map> 8 #include<stack> 9 #include<vector> 10 #include<queue> 11 #include<string> 12 #include<sstream> 13 #define eps 1e-9 14 #define ALL(x) x.begin(),x.end() 15 #define INS(x) inserter(x,x.begin()) 16 #define FOR(i,j,k) for(int i=j;i<=k;i++) 17 using namespace std; 18 typedef long long LL; 19 int i,j,k,n,m,x,y,T,ans,big,cas,a[1005],b[1005]; 20 bool flag; 21 double dp[1005],d[1005]; 22 double run(double u) 23 { 24 double cur=0; 25 for (int i=1;i<=n;i++) d[i]=a[i]-u*b[i]; 26 sort(d+1,d+1+n); 27 for (i=m+1;i<=n;i++) cur+=d[i]; 28 return cur; 29 } 30 31 int main() 32 { 33 while (scanf("%d%d",&n,&m),n+m) 34 { 35 for (i=1;i<=n;i++) scanf("%d",&a[i]); 36 for (i=1;i<=n;i++) scanf("%d",&b[i]); 37 double l=0,r=1; 38 while (r-l>eps) 39 { 40 double mid=(l+r)/2; 41 if (run(mid)>0) l=mid; 42 else r=mid; 43 } 44 printf("%d ",(int)(r*100+0.5)); 45 } 46 return 0; 47 }
Dinkelbach算法(牛顿迭代法) 32MS
事先随意确定一个数,然后逼近正确答案。
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<iostream> 5 #include<algorithm> 6 #include<set> 7 #include<map> 8 #include<stack> 9 #include<vector> 10 #include<queue> 11 #include<string> 12 #include<sstream> 13 #define eps 1e-9 14 #define ALL(x) x.begin(),x.end() 15 #define INS(x) inserter(x,x.begin()) 16 #define FOR(i,j,k) for(int i=j;i<=k;i++) 17 using namespace std; 18 typedef long long LL; 19 struct node 20 { 21 double num; 22 int i; 23 }d[1005]; 24 int i,j,k,n,m,x,y,T,big,cas,a[1005],b[1005]; 25 bool flag; 26 double l,ans; 27 LL p,q; 28 bool cmp(node a,node b) 29 { 30 return a.num<b.num; 31 } 32 int main() 33 { 34 while (scanf("%d%d",&n,&m),n+m) 35 { 36 for (i=1;i<=n;i++) scanf("%d",&a[i]); 37 for (i=1;i<=n;i++) scanf("%d",&b[i]); 38 l=1;ans=0; 39 while (fabs(l-ans)>eps) 40 { 41 ans=l; 42 for (i=1;i<=n;i++) 43 { 44 d[i].num=a[i]*1.0-l*b[i]; 45 d[i].i=i; 46 } 47 sort(d+1,d+1+n,cmp); 48 p=q=0; 49 for (i=m+1;i<=n;i++) 50 { 51 p+=a[d[i].i]; 52 q+=b[d[i].i]; 53 } 54 l=p*1.0/q; 55 } 56 printf("%d ",(int)(ans*100+0.5)); 57 } 58 return 0; 59 }
注意Dinkelbach算法中p,q要使用long long