zoukankan      html  css  js  c++  java
  • [ACM_其他] 总和不小于S的连续子序列的长度的最小值——尺缩法

    Description:

    给定长度为n的整数数列,A[0],A[1],A[2]….A[n-1]以及整数S,求出总和不小于S的连续子序列的长度的最小值。如果解不存在,则输出0。

    Input:

    输入数据有多组,每组数据第一行输入n,S, (10<n<10^5,S<10^8)第二行输入A[0],A[1],A[2]….A[n-1] ( 0<A[i]≤10000),处理到文件结束。所有输入数据都在int范围之内。

    Output:

    每组数据输出结果占一行。

    Sample Input:

    10 15
    5 1 3 5 10 7 4 9 2 8
    

    Sample Output:

    2


    >>>>>>>>>这题有一个技巧,叫做尺缩法
    -----------------------------------------------------------------------------------------------------------------------

    (1)   设置两个指针s和t,一开始都指向数列第一个元素,此外sum=0,res=0;

    (2)   只要sum<S,就将sum增加一个元素,t加1;

    (3)   直到sum>=S,更新res=min(res,t-s);

    (4)   将sum减去一个元素,s加1,执行(2)。

    上述流程反复地推进区间的开头和末尾,来求取满足条件的最小区间。

    ----------------------------------------------------------------------------------------------------------------------------------------------------------

    #include<iostream>
    using namespace std;
    int min(int a,int b){if(a>b)return b;return a;}
    int main(){
        int n,S,A[100005];
        int i,j,k;
        while(cin>>n>>S){
            //输入数据部分
            for(int i=0;i<n;i++)cin>>A[i];
            //尺缩法计算部分
            int res=n+1,s=0,t=0,sum=0;
            for(;;){
                while(t<n && sum<S)sum+=A[t++];
                if(sum<S)break;
                res=min(res,t-s);
                sum-=A[s++];
            }
            if(res>n)res=0;
            //输出结果
            cout<<res<<'
    ';
        }
        return 0;
    }
    View Code

    >>>>>>>>> 同样也可以用用lower_bound:

       --------------------------------------------------------------------------------------------------------------------------------------------------------

       lower_bound(ForwardIterator first,ForwardIterator last, const Type &value,Compare comp );

     lower_bound()返回一个 iterator 它指向在[first,last)标记的有序序列中可以插入value,而不会破坏容器顺序的第一个位置,而这个位置标记了一个大于等于value 的值。

       例如,有如下序列:

       ia[]={12,15,17,19,20,22,23,26,29,35,40,51};
       用值21调用lower_bound(),返回一个指向22的iterator。用值22调用lower_bound(),也返回一个指向22的iterator。根据comp进行排序和比较。
     注意:::调用lower_bound之前必须确定序列为有序序列,否则调用出错。函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于    val的第一个元素位置。如果所有元素都小于val,则返回last的位置。
       --------------------------------------------------------------------------------------------------------------------------------------------------------
       所以这里我们可以这样处理:

       我们可以计算出sum(i)=a0+a1+...+ai。那么sum(t)-sum(s)=as+a(s+1)+...a(t-1)。这样我们可以实现先求出一个sum(n)。sum(n)-sum(i)=s。我们只需要去筛选sum(i)。这样可以用二分搜索的方法快速求出最小的长度。

    int t=lower_bound(sum+i,sum+n,sum[i]+s)-sum;求出来的是从ai到at(i<=t<=n)和比s小的最小值的下标。

     1 #include<algorithm>
     2 using namespace std;
     3 int min(int a,int b){if(a>b)return b;return a;}
     4 int n,s;
     5 int a[100005];
     6 int sum[100005];
     7 int main(){
     8     while(cin>>n>>s){
     9         //sum归0;
    10         memset(sum,0,sizeof(sum));
    11         //输入并计算sum;
    12         for(int i=0;i<n;i++){
    13             cin>>a[i];
    14             sum[i+1]=sum[i]+a[i];
    15         }
    16         //运算求解输出;
    17         if(sum[n]<s){
    18             cout<<"0"<<endl;
    19         }
    20         else{
    21             int ret=n;
    22             for(int i=0;sum[i]+s<=sum[n];i++){          
    23                 int t=lower_bound(sum+i,sum+n,sum[i]+s)-sum;
    24                 ret=min(ret,t-i);
    25             }
    26             cout<<ret<<endl;
    27         }
    28     }
    29     return 0;
    30 }
    View Code

    >>>>>>>>附加:折半查找法:

     1 int lowerBound(int array[],int left,int right,int value)
     2 {
     3         int mid=0,half=0;
     4         int len=(right+left+1)/2;
     5         while(len>0)
     6         {
     7                 half=len>>1;          //数据长度折半
     8                 mid=left+half;        //计算中点
     9                 if (array[mid]<value) //调整总长与起点
    10                 {
    11                         len=len-half-1;
    12                         left=mid+1;
    13                 }
    14                 else
    15                         len=half;
    16         }
    17         return left;
    18 }
    lower_bound版本一:
     1 int lowerBound(int array[],int left,int right,int value)
     2 {
     3         int mid=0;
     4         while(left<right)
     5         {
     6                 mid=(right+left)/2;       //计算中点
     7                 if (array[mid]<value)     //调整起点或者终点
     8                         left=mid+1;
     9                 else
    10                         right=mid;
    11         }
    12         return right;
    13 }
    lower_bound版本二:
     1 int upperBound(int array[],int left,int right,int value)
     2 {
     3         int mid=0,half=0;
     4         int len=(right+left+1)/2;
     5         while(len>0)
     6         {
     7                 half=len>>1;         //长度折半
     8                 mid=left+half;       //计算中点
     9                 if (array[mid]>value) //调整长度与起点
    10                         len=half;
    11                 else
    12                 {
    13                         len=len-half-1;
    14                         left=mid+1;
    15             }
    16         }
    17         return left;
    18 }
    upper_bound版本一:
     1 int upperBound(int array[],int left,int right,int value)
     2 {
     3         int mid=0;
     4         while(left<right)
     5         {
     6                 mid=(right+left)/2;    //计算中点
     7                 if (array[mid]>value)  //调整起点或者终点
     8                         right=mid;
     9                 else
    10                         left=mid+1;
    11         }
    12         return right;
    13 }
    upper_bound版本二:
     1 int binarySearch(int array[],int left,int right,int value)
     2 {
     3         int mid;
     4         while(left<=right)
     5         {
     6                 mid=(left&right)+((left^right)>>1);      //防止溢出
     7                 if(array[mid]==value)
     8                         return mid;
     9                 else if (array[mid]<value)
    10                         left=mid+1;
    11                 else
    12                         right=mid-1;
    13         }
    14         return -1;
    15 }
    折半查找:
     
  • 相关阅读:
    经典SQL问题: 行转列,列转行
    RocketMQ之三:RocketMQ集群环境搭建
    mysql函数之五:group_concat mysql 把结果集中的一列数据用指定分隔符转换成一行
    并发编程之五--ThreadLocal
    RocketMQ之三:nameserver源码解析
    Spring之3:BeanFactory、ApplicationContext、ApplicationContextAware区别
    spring中InitializingBean接口使用理解
    ES之四:Elasticsearch Mapping类型映射概述与元字段类型
    spring容器启动的三种方式
    java的reflection和introspector
  • 原文地址:https://www.cnblogs.com/zjutlitao/p/3485545.html
Copyright © 2011-2022 走看看