二分查找(2)
//poj 3273 Monthly Expense
/*
題意:給你天數n,和每天需要花的錢,讓你把這些天分成m份(每份都是連續的天),
要求每份的和盡量少,輸出這個和。
一開始二分的上界為n天花費的總和(相當于分成1份),下界為每天花費的最大值(相當于分成n份),
然后二分,每次的mid值為(上界 + 下界)/ 2,然后根據mid值遍歷n天花費,對花費進行累加,
每當超過mid值 份數++,看看這個mid值能把n天分成幾份,如果份數大于m,表示mid偏小,下界 = mid + 1,
反之小于等于mid,上界 = mid,然后輸出最后的mid值即可,復雜度為 O(nlogM)
*/
#include <iostream>
using namespace std;
int list[100010];
int main()
{
int n,m,i,max=0,sum=0;
cin>>n>>m;
for(i=0;i<n;++i)
{
cin>>list[i];
sum+=list[i];
if(list[i]>max)
max=list[i];
}
int low=max,high=sum,mid,s,t;
while(low<high)
{
mid=(low+high)/2;
s=0;t=0;
for(i=0;i<n;++i)
{
s+=list[i];
if(s>mid)
{
t++;
s=list[i];
}
if(t>m)break;
}
if(s>0) //注意這句
t++;
if(t<=m)
//若t==m,此時不能斷定m是最小的,可能有比它更小的數也符合,具有單調性,所以需要繼續搜索前半部分
high=mid;
//這里不寫成high=mid+1;因為可能除了mid符合外,并沒有比它小的數也符合
else
low=mid+1;
//因為low<=mid<high,所以high=mid,low=mid+1,都會不斷地縮小范圍,最終low==high,跳出循環
}
cout<<low<<endl;
return 0;
}
//對應于 0011序列中最左側的1的查找(最小值):
//http://duanple.blog.163.com/blog/static/709717672009049528185/
/*
題意:給你天數n,和每天需要花的錢,讓你把這些天分成m份(每份都是連續的天),
要求每份的和盡量少,輸出這個和。
一開始二分的上界為n天花費的總和(相當于分成1份),下界為每天花費的最大值(相當于分成n份),
然后二分,每次的mid值為(上界 + 下界)/ 2,然后根據mid值遍歷n天花費,對花費進行累加,
每當超過mid值 份數++,看看這個mid值能把n天分成幾份,如果份數大于m,表示mid偏小,下界 = mid + 1,
反之小于等于mid,上界 = mid,然后輸出最后的mid值即可,復雜度為 O(nlogM)
*/
#include <iostream>
using namespace std;
int list[100010];
int main()
{
int n,m,i,max=0,sum=0;
cin>>n>>m;
for(i=0;i<n;++i)
{
cin>>list[i];
sum+=list[i];
if(list[i]>max)
max=list[i];
}
int low=max,high=sum,mid,s,t;
while(low<high)
{
mid=(low+high)/2;
s=0;t=0;
for(i=0;i<n;++i)
{
s+=list[i];
if(s>mid)
{
t++;
s=list[i];
}
if(t>m)break;
}
if(s>0) //注意這句
t++;
if(t<=m)
//若t==m,此時不能斷定m是最小的,可能有比它更小的數也符合,具有單調性,所以需要繼續搜索前半部分
high=mid;
//這里不寫成high=mid+1;因為可能除了mid符合外,并沒有比它小的數也符合
else
low=mid+1;
//因為low<=mid<high,所以high=mid,low=mid+1,都會不斷地縮小范圍,最終low==high,跳出循環
}
cout<<low<<endl;
return 0;
}
//對應于 0011序列中最左側的1的查找(最小值):
//http://duanple.blog.163.com/blog/static/709717672009049528185/
轉載于:https://www.cnblogs.com/mjc467621163/archive/2011/08/22/2149189.html
總結
- 上一篇: css背景渐变的技巧与方法
- 下一篇: 自适应高度Textarea