zoukankan      html  css  js  c++  java
  • poj 2018 Best Cow Fences USACO历年月赛 (分数规划+DP)

    题目链接:http://poj.org/problem?id=2018

    大致题意:在N (1 <= N <= 100,000)块田中,选取一个长度不短于 F (1 <= F <= N)的连续区间,使得这个区间的平均值最大。

    Time Limit: 1000MS Memory Limit: 30000K

    样例:

    Sample Input

    10 6
    6 
    4
    2
    10
    3
    8
    5
    9
    4
    1
    

    Sample Output

    6500

     

    思路:看这个题目我们很容易想到O(n^2)的DP状态转移方程。但是这个N的范围是10^5,O(n^2)严重超时。此题的一种解法是斜率优化DP(求平均值最大是维护凸包的过程,故存在斜率优化策略)。另外一种解法是01分数规划。

    这里讲一下第二种的思路,假定我们已经知道最大的平均值(平均值在这个数组的最大数和最小数之间),所有的数都减去这个平均值,那么我们就能求出一个最大连续子段的和跟0做比较,如果字段和大于0,说明我们假设的这个最大平均值偏小了,如果小于0则偏大。我们可以通过二分平均值,找到答案。这样我们就把原来的求平均值的问题转化为求长度限制的连续子段和问题了。时间复杂度是O(lgN),N跟需要的精度有关。分数规划思路就是假设答案,推出答案的组成。

    长度不小于f的最大连续字段和比最大连续字段和多加了一个长度限制的条件,其实我们只要保证这个序列长度至少是f就可以了。

    状态转移方程是:dp[i]=max(num[i],dp[i-f]+num[i]),dp[i]是指去掉i前面f-1个数的最大连续子段和,dp[i]+num[i-f]+num[i-f+1]+...+num[i-1]就是保证长度至少为f的以num[i]为结尾的最大连续字段和。时间复杂度是O(N)。

    总的时间复杂度是O(N*lgN)。

     

     1 #include<cstdio>
     2 const double inf=1e-6;
     3 const int MAXNUM=100005;
     4 double num[MAXNUM];
     5 double temp[MAXNUM];
     6 double dp[MAXNUM];
     7 double max(double a,double b){
     8     if(a>b)return a;
     9     return b;
    10 }
    11 double min(double a,double b){
    12     if(a<b)return a;
    13     return b;
    14 }
    15 int main(){
    16     int n,f,i,j;
    17     double left,right,mid;
    18     while(~scanf("%d%d",&n,&f)){
    19         left=2000,right=0;
    20         for(i=0;i<n;i++){
    21             scanf("%lf",&num[i]);
    22             left=min(num[i],left);
    23             right=max(right,num[i]);
    24         }
    25         while(right-left>inf){
    26             mid=(right+left)/2;
    27             for(i=0;i<n;i++)temp[i]=num[i]-mid;
    28             dp[0]=temp[0];
    29             for(i=1;i<f;i++)dp[i]=max(temp[i],dp[i-1]+temp[i]);
    30             double ans=0,sum=0;
    31             for(i=1;i<f;i++)sum+=temp[i];
    32             for(i=0;i<f;i++)ans+=temp[i];
    33             for(i=f;i<n;i++){
    34                 dp[i]=max(temp[i],dp[i-f]+temp[i]);
    35                 ans=max(ans,sum+dp[i]);
    36                 sum=sum-temp[i-f+1]+temp[i];
    37             }
    38              if(ans>0)left=mid;
    39             else right=mid;
    40         }
    41         int ans=1000*right;
    42         printf("%d\n",ans);
    43     }
    44     return 0;
    45 }
  • 相关阅读:
    Ui设计哪里有好的素材
    android重写view和viewgroup的区别
    笔记本电脑连接wifi有时候会自动断网提示有限的访问权限解决办法
    ADT 怎么删除logcat过滤规则
    Android开发在使用第三方推送的时候出现INSTALL_FAILED_VERSION_DOWNGRADE
    评论的延迟加载(转载)
    让Entity Framework支持MySql数据库(转载)
    Net4.0---AspNet中URL重写的改进(转载)
    Entity Framework 使用
    深入浅出JSONP--解决ajax跨域问题
  • 原文地址:https://www.cnblogs.com/mcflurry/p/2623277.html
Copyright © 2011-2022 走看看