二分法(二):采用二分法解決“最小化最大值問題”


      二分法除了可以進行有序查找、解方程等外,還可以用來解決一些實際問題。這些問題中,非常典型的應用就是“最小化最大值問題”和“最大化最小值問題”

      最小化最大值問題最大化最小值問題在優化問題中比較常見,簡單來說,最小化最大值是為了壓制優化目標中表現最突出的成分,最大化最小值為了提升優化目標中表現最差的成分。

      (1)最小化最大值問題

      一般來說,優化時考慮的是目標函數的最大化或最小化的問題。但是在某些情況下,則要求最大值的最小化才有意義。例如,在城市規划中需要確定急救中心、消防中心的位置,可取的目標函數應該是到所有地點最大距離的最小值(即急救中心、消防中心的建設位置應保證它到最遠需求點的距離盡可能小),而不是到達所有目的地距離和的最小值。因為城市同時發生事故或同時着火的幾率極低,因此更多應該考慮如何降低最惡劣情況的影響,即使是最遠的地方出事了,中心到它們的距離也能達到最小。

      (2)最大化最小值問題

      這個問題在通信鏈路中應用比較多,如基站同時和多用戶通信,每個基站到用戶的通信為一個通信鏈路,且基站的發射功率是固定的。為了保證所有的通信鏈路都正常工作,應該去優化最差鏈路的通信情況,降低信道較好鏈路的基站發射功率,增加信道較差鏈路的基站發射功率,這是一個最大化最小值問題。

 【例1】數列分段。

題目描述

對於給定的一個長度為N的正整數數列A-i,現要將其分成M(M≤N)段,並要求每段連續,且每段和的最大值最小。

關於最大值最小:

例如一數列4 2 4 5 1要分成3段

將其如下分段:

[4 2] [4 5] [1]

第1段和為6,第2段和為9,第3段和為1,和最大值為9。

將其如下分段:

[4] [2 4] [5 1]

第1段和為4,第2段和為6,第3段和為6,和最大值為6。

並且無論如何分段,最大值不會小於6。

所以可以得到要將數列4 2 4 5 1要分成3段,每段和的最大值最小為6。

輸入輸出格式

輸入格式:

第1行包含兩個正整數N,M(N≤100000,M≤N)。

第2行包含N個空格隔開的非負整數Ai(Ai之和不超過10^9)

輸出格式:

一個正整數,即每段和最大值最小為多少。

輸入輸出樣例

輸入樣例#1: 

5 3

4 2 4 5 1

輸出樣例#1: 

6

      (1)編程思路。

      要解決這個最小化最大值的問題,基本思路就是選取任意一個范圍(輸入數組的最大值到數組所有元素的和),然后在這個范圍內進行二分法,每次把范圍的中間值mid當作最小值,然后判斷在mid值下數組是否能夠被分為m個部分。如果判斷出值為mid時可以將數組分成m個部分,就先讓mid變大再試試,即增大下界(left=mid+1);如果分不成m個部分,說明當前的mid太大了,就先讓mid變小再進行判斷,即減小上界(right=mid)。直到求出一個最大的mid就是最終的答案。

      (2)源程序。

#include <stdio.h>

int n,m;

int a[100000];

bool judge(int mid)

{

     int sum=0;

     int count=0;

     for(int i=0;i<n;i++)

     {

             sum += a[i];

             if(sum>mid)

             {

                 sum=a[i];

                 count++;        

             }

     }

     if ((count+1)<=m)

        return 1;

     return 0;

}

int main()

{

    scanf("%d%d",&n,&m);

    int left=-1,right=0,mid,i;

    for(i=0;i<n;i++)

    {

       scanf("%d",&a[i]);   

       right += a[i];

       if(a[i]>left)

       {

          left = a[i];            

       }

    } 

    while(left<right)

    {

         mid=(left+right)/2;

         if(judge(mid))

         {

            right = mid;               

        }

        else

        {

          left = mid+1;

        }

    }

    printf("%d\n",left);

   return 0;

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM