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\n",(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\n",(int)(ans*100+0.5));

57     }

58     return 0;

59 }
View Code

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

你可能感兴趣的:(test)