zoukankan      html  css  js  c++  java
  • 01分数规划

    这几天就水水博客把以前学过的东西整理一下,其实感觉还是比较有必要的,很多东西学了之后很快就忘了QAQ不知是不是我太蠢

    https://vjudge.net/problem/POJ-2976

    题意:给定A数组B数组,从中选择N-K个使得R最大,输出Round(100*R);

    01分数规划问题就是给定两个数组A和B,让你找出m个i使得∑A[i]/∑B[i]最大

    我们设∑A[i]/∑B[i]=L,F(L)=∑A[i]-L*∑B[i]

    若F[L]大于0,则存在更大的L,否则L只能减小,所以我们二分这个L

    【法一】 直接二分L,算出每个i的A[i]-L*B[i],排序后取最大的m个,若和大于0则l=mid,否则r=mid;

    //Twenty
    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<queue>
    #include<vector>
    const int maxn=1005;
    int ans,n,k;
    double sum,mid,l=1e9,r=-1e9,eps=1e-7;
    struct node{
        double a,b,d;
        friend bool operator <(const node&A,const node&B){
           return A.d<B.d;
        }
    }N[maxn];
    using namespace std;
    int check(double L){
        sum=0;
        for(int i=1;i<=n;i++) N[i].d=N[i].a-L*N[i].b;
        sort(N+1,N+n+1);
        for(int i=k+1;i<=n;i++)
        sum+=N[i].d;
        return sum>0;
    }
    int main()
    {
        for(;;){
          scanf("%d%d",&n,&k);
          if(!n&&!k) break;
          for(int i=1;i<=n;i++) scanf("%lf",&N[i].a);
          for(int i=1;i<=n;i++) scanf("%lf",&N[i].b);
          for(int i=1;i<=n;i++){
              l=min(l,N[i].a/N[i].b);
              r=max(r,N[i].a/N[i].b);
          }
          while(r-l>eps){
            mid=(l+r)/2;
            if(check(mid)) l=mid;
            else r=mid;
          }
          ans=floor(l*100+0.5);
          printf("%d
    ",ans);
        }
       return 0;
    }
    二分 01分数规划

    【法二】Dinkelbach 

    一种神奇的算法,感觉学一次忘一次,今天又粗略的看了一下,就随便口胡一下。

    我们先随便确定一个L,然后求出一个F(L),若它大于0,那么证明F(L)是一个比L更优的解,那么我们直接把解移到F(L)上去。这样一直移动直到达到精度要求。

    //Twenty
    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<queue>
    #include<vector>
    const int maxn=1005;
    int an,n,k;
    double x,y,ans,L,sum,mid,l=1e9,r=-1e9,esp=1e-7;
    struct node{
        double a,b,d;
        friend bool operator <(const node&A,const node&B){
           return A.d<B.d;
        }
    }N[maxn];
    using namespace std;
    void work(){
       ans=0;
       for(;;){
        x=0;y=0;
           for(int i=1;i<=n;i++) N[i].d=N[i].a-ans*N[i].b;
           sort(N+1,N+1+n);
           for(int i=k+1;i<=n;i++) x+=N[i].a,y+=N[i].b;
           L=x/y;
           if(fabs(L-ans)<=esp) return;
           ans=L;
       }   
    }
    int main()
    {
        for(;;){
          scanf("%d%d",&n,&k);
          if(!n&&!k) break;
          for(int i=1;i<=n;i++) scanf("%lf",&N[i].a);
          for(int i=1;i<=n;i++) scanf("%lf",&N[i].b);
          work(); 
          an=floor(ans*100+0.5);
          printf("%d
    ",an);
        }
       return 0;
    }
    Dinkelbach
  • 相关阅读:
    位运算符设置权限
    urlencode、urldecode、rawurlencode、rawurldecod
    二分查找法的mid值 整数溢出问题
    GIT 常用命令
    nginx配置反向代理转发
    PHP实现无限极分类
    PHP面试题目整理(持续更新)
    去除input的默认样式
    git 常用指令
    数组去重
  • 原文地址:https://www.cnblogs.com/Achenchen/p/7473724.html
Copyright © 2011-2022 走看看