晓轩

博客园 首页 联系 订阅 管理

把一个包含n个正整数的序列划分成m个连续的子序列。设第i个序列的各数之和为S(i),求所有S(i)的最大值的最小值是多少?例如序列1 2 3 2 5 4划分为3个子序列的最优方案为 1 2 3 | 2 5 | 4,其中S(1),S(2),S(3)分别为6,7,4,最大值为7;如果划分为1 2 3|2|5 4,最大值为9,不是最小。

问题分析:能否使m个连续的子序列的和S(i)<=x,(i=1,2..m),则满足命题的最小x即为所求,可以采用贪心法,从左到右尽可能多的划分元素,可以把问题转化为递归分治问题,采用2分法,取n个正整数的和与n个正整数的最大值的中值x,若命题成立,则所求解小于等于x,若命题不成立,所求解大于x,2分递推求解,时间复杂度为O(n*logSum);

代码如下:

  1. #include<iostream>
    using namespace std;
    const int MAX=100;
    int a[MAX];
    int n,m;

    bool Judge(int x)
    {
     int s=0,cnt=0;
     for(int i=0;i<n;i++)
     {
      if(x<a[i])
       return false;
      if(s+a[i]<=x)
       s+=a[i];
      else
      {
       s=a[i];
       cnt++;
       if(cnt>m-1)
        return false;
      }
     }
     return true;
    }

    int Solve(int lo,int hi)
    {
     int mid;
     while(lo<hi)
     {
      mid=lo+(hi-lo)/2;
      if(Judge(mid))
       hi=mid;
      else
       lo=mid+1;
     }
     return lo;
    }

    int main()
    {
     int max,sum,T;
     cin>>T;
     while(T--)
     {
      cin>>n>>m;
      if(m>n)
       m=n;
      max=0;
      sum=0;
      for(int i=0;i<n;i++)
      {
       cin>>a[i];
       if(max<a[i])
        max=a[i];
       sum+=a[i];
      }
      cout<<Solve(max,sum)<<endl;
     }
     return 0;
    }

 

posted on 2013-05-13 16:07  晓轩  阅读(1544)  评论(0)    收藏  举报