1. 程式人生 > >二分法初次嘗試

二分法初次嘗試

//刷二分法的第一道題目,搞懂它搞了3個多小時,惡補了二分法的基礎上終於理解了,不容易,欲速則不達,必須具備相應的基礎,否則過於生硬。

#include<iostream>
#include<cstdio>
using namespace std;
int a[1000000];
int judge(int mid,int a[],int n,int m)
{
    int i;
    int sum=0;
    int t=1;//這裡初值寫成了t=0,實際下面的操作中導致了少算了一次。
    for(i=1;i<=n;i++)
    {
        if(a[i]+sum>mid)
        {
            sum=a[i];
            t++;
        }
        else sum=sum+a[i];
    }
    if(t>m)
        return 1;
    else return 0;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    int i;
    int maxn=0,total=0;
    for(i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        if(a[i]>maxn)
            maxn=a[i];
        total+=a[i];
    }
    int l=maxn;
    int r=total;
    int mid;
    while(l<=r)
    {
        mid=(l+r)/2;
        if(judge(mid,a,n,m))l=mid+1;
        else r=mid-1;
    }
    cout<<l<<endl;//,這裡錯了,寫成了mid這裡需要考慮的是最後一次是l與r相等的情況下,下一次就結束了,所以是最後一次了,這時候如果返回的次數正好多餘要求的次數即返回1的情況下,
    //我們需要回到正好的狀態就是讓l+1,這個相當於是一個回溯的操作,即尋找可能性失敗後的回退機制,所以這裡是輸出l,當然如果最後r與l相等的情況下
    //如果返回的仍然是0,這個時候就是最佳狀態了,返回mid和l是一樣的。(以上分析錯誤的原因主要是二分法操作不熟練導致,欲速不達,二分法必須熟練掌握才能
    //完全解決各種的子段最少的最大題。)
    return 
}