POJ 2976 Dropping tests 01分数规划

给出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 }
View Code

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 }
View Code

注意Dinkelbach算法中p,q要使用long long

原文地址:https://www.cnblogs.com/zhyfzy/p/4113682.html