最大值最小化问题

来源:互联网 发布:怎么做淘宝 编辑:程序博客网 时间:2024/06/06 08:20

文章参考:http://blog.csdn.net/nanjunxiao/article/details/8145971

问题描述:

把一个包含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,则该命题成立的最小的x即为答案。该命题不难判断,只需贪心,每次尽量从左

向右尽量多划分元素即可。

我们把该问题转化为递归分治问题,类似于二分查找。首先取Sum和元素最大值的中值x,如果命题为假,那么答案比x大;

如果命题为真,则答案小于等于x。问题得解,复杂度为O(n*logSum)


代码参考:http://blog.csdn.net/nomad2/article/details/7833299

二分法:

[cpp] view plain copy
  1. #include <iostream>  
  2. #include <ctime>  
  3. using namespace std;  
  4. #define N 10  
  5. #define INF 1000  
  6.   
  7. int juge(int a[],int mid,int k)  
  8. {  
  9.     int i;  
  10.     int seg=0;  
  11.     int sum=0;  
  12.     for(i=0;i<N;i++)  
  13.     {  
  14.         sum+=a[i];  
  15.         if(sum>mid)        //从左到右将数组元素之和与mid比较,如是大于则再起一段,最后看段的大小  
  16.         {  
  17.             sum=a[i];  
  18.             seg++;  
  19.         }  
  20.     }  
  21.     if(seg>=k)    //若是段超过3,则必然不和条件  
  22.         return 0;  
  23.     else  
  24.         return 1;  
  25. }  
  26.   
  27. int value(int a[],int low,int high,int segment)        //分治法求解  
  28. {  
  29.     if(low>high)  
  30.         return high+1;  
  31.     else  
  32.     {  
  33.         int mid=(low+high)/2;  
  34.         if(juge(a,mid,segment)==1)        //如果试验数mid符合要求,递归到前一半  
  35.             return value(a,low,mid-1,segment);  
  36.         else                            //如果试验数mid不符合要求,递归到后一半  
  37.             return value(a,mid+1,high,segment);  
  38.     }  
  39. }  
  40.   
  41. int main()  
  42. {  
  43.     srand((unsigned)time(NULL));  
  44.     int a[N];  
  45.     for(int ifor=0;ifor<N;ifor++)  
  46.         a[ifor]=rand()%20;  
  47.     for(ifor=0;ifor<N;ifor++)  
  48.         cout<<a[ifor]<<" ";  
  49.   
  50.     //int a[N]={9,19,15,13,13,9,14,1,1,7};  
  51.      int m=3;  
  52.     cout<<endl;  
  53.     //求出队列中所有数的和max,还要求出当中最小的数min  
  54.     int min=INF,max=0;  
  55.     for(int i=0;i<N && a[i]!=' ';i++)  
  56.     {  
  57.         max+=a[i];  
  58.         if(a[i]<min)  
  59.             min=a[i];  
  60.     }  
  61.     cout<<endl;  
  62.     int tem=value(a,min,max,m);        //调用value函数求值  
  63.     cout<<tem<<endl;  
  64.       
  65.     return 0;  
  66. }  

原创粉丝点击