最优子序列问题(减而治之 - 二分查找 - 分组)
Posted ziyang1060
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最优子序列问题(减而治之 - 二分查找 - 分组)相关的知识,希望对你有一定的参考价值。
1 #include<stdio.h> 2 #include<stdlib.h> 3 int isSright(int *arr,int N,int M,int S);//判断S是否可能为数列分组的和 4 int dichotomy(int *arr,int N,int M);//对S的上下限使用二分法 5 int main(void) 6 { 7 int*arr,N,M,i;//n个数字,m份 8 9 scanf("%d %d",&N,&M); 10 arr=(int*)malloc(sizeof(int)*N);//动态分配内存 11 for(i=0;i<N;i++) 12 scanf("%d",arr+i); 13 printf("%d ",dichotomy(arr,N,M)); 14 free(arr); 15 arr=NULL; 16 17 return 0; 18 } 19 int isSright(int *arr,int N,int M,int S) 20 { 21 int j=0; 22 int currentS=0;//尝试分割过程中,当前分割的部分和 23 int sum=1;// 记录尝试分割过程中已分的份数 24 for(j=0;j<N;j++) 25 { 26 if(*(arr+j)>S) return 0;//如果出现单个元素超过S直接返回0 27 currentS+=arr[j]; 28 if(currentS>S) 29 { 30 currentS=0; 31 sum++; 32 j--; 33 } 34 } 35 if(sum>M) return 0; 36 else return 1; 37 } 38 int dichotomy(int *arr,int N,int M)//二分法 39 { 40 int i=0; 41 int left=0,right=0,middle=0; 42 for(i=0;i<N;i++) 43 right+=*(arr+i); 44 while(left<=right) 45 { 46 middle=(left+right)/2; 47 if(isSright(arr,N,M,middle)==1) right=middle-1; 48 else left=middle+1; 49 } 50 return left; 51 }
明确两点:第一,该数列是正整数列,S的最大值应为全部数字的和,所以S的上限很容易
确定。只要我确定当前S的可行性,就能确定下一个S的范围,由此想到
可以利用二分法来完成。
第二,对于每个S可行性的检查,在数组中按原顺序一直累加,直至恰好不超过
S,开辟一个新的起点,继续加和,再将总的开辟数与M份数进行比较。
PS:感觉自己越来越适应计算思维,从一开始的一窍不通,到后面愿意花时间反复研究,自
己的进步很明显。虽然我现在仍然和dalao有很大差距,但是我看到了希望。
加油,Ziyang!
以上是关于最优子序列问题(减而治之 - 二分查找 - 分组)的主要内容,如果未能解决你的问题,请参考以下文章