利用二分的思想求最值問題

在求最值問題裏,我們最常見的方法是動態規劃,回朔法。然而二分思想也是能夠解決某一類最值問題,而且這一類最值問題會用明顯的特徵。

先來看題目hiho第38周題目:http://hihocoder.com/contest/hiho38/problem/1

將該題目稍微簡化模型,意思就是求點到點的最長路徑邊的最小值。該題目是不能用動態規劃的,因爲並不存在動態轉移方程。因此只能用回朔法。但是這類題目有明顯的特徵就是:我們一個確定2個值,left_value,right_value,left_value一定不滿足題目要求,而right_value則一定滿足題目要求。故我們要找的最小值一定是在區間[left_value,right_value]內,一點有序區間去尋找某個值就可以用二分的思想。該替思路如下:

           

              

  其中打紅色方框的就是該類型題目的共性,不同的則是需要根據題意,編寫不同的f(x)函數。

該題源代碼(已accept)如下:

#include<cstdio>
#include<cstring>
#include<queue>
#include<utility>
#include<vector>
#include<algorithm>
#define PMAXN 10010
#define GMAXN 200010
using namespace std;

struct edge
{
    int id;
    int next;
    int value;
   // edge(int value,int _id=0,int _next=-1):id(_id),next(_next){}
};

int pnode[PMAXN];  //用來存放點
edge lines[GMAXN]; //用來存放邊
bool vis[PMAXN];
int lines_index=0;    //邊數組的索引下標
int n,m,k,t;

int key[GMAXN]; //用來存放邊權
int key_index=0;

void add(int l,int r,int value)
{
    lines[lines_index].id=l;
    lines[lines_index].next=pnode[r];
    lines[lines_index].value=value;
    pnode[r]=lines_index++;
    lines[lines_index].id=r;
    lines[lines_index].next=pnode[l];
    lines[lines_index].value=value;
    pnode[l]=lines_index++;
}
//不能使用深搜,會超時,因爲深搜會使用遞歸,數據太大真不好用
bool f(int x)
{
    memset(vis,false,sizeof(vis));
    queue<pair<int,int> > q;
    q.push(make_pair(1,0));
    vis[1]=true;
    while(!q.empty())
    {
        int node=q.front().first;
        int num=q.front().second;
        if(num>=k)
            return false;
        q.pop();
        for(int i=pnode[node];i!=-1;i=lines[i].next)
        {
            if(lines[i].value>x||vis[lines[i].id])
                continue;
            if(lines[i].id==t)
                return true;
            q.push(make_pair(lines[i].id,num+1));
            vis[lines[i].id]=true;;
        }
    }
    return false;

}

int BinaryAnswer(int left,int right)
{
    if(left==right-1)
        return right;
    int mid=(left+right)/2;
    if(f(key[mid]))
        return BinaryAnswer(left,mid);
    else
        return BinaryAnswer(mid,right);
}
int main()
{
    freopen("a.txt","r",stdin);
    scanf("%d%d%d%d",&n,&m,&k,&t);
    for(int i=0;i<=n;i++)
        pnode[i]=-1;
    for(int i=0;i<m;i++)
    {
        int l,r,value;
        scanf("%d%d%d",&l,&r,&value);
        key[key_index++]=value;
        add(l,r,value);
    }
    sort(key,key+key_index);
    int *p=unique(key,key+key_index);
    key_index=p-key;
    if(f(key[0]))
        printf("%d",key[0]);
    else
        printf("%d",key[BinaryAnswer(0,key_index-1)]);
    return 0;
}

來看一到hiho上微軟面試題,同樣使用的是二分搜索。 http://hihocoder.com/problemset/problem/1095

源代碼(已accept)如下:

#include<cstdio>
#define maxn 100010
int n,k;
int d[maxn]; //每一次的隨機數
int hi,ho,ho_cup;
//true表示小ho贏
bool f(int t)
{
    hi=0,ho=0;
    int ho_cup=t;
    for(int i=0;i<n;i++)
    {
        if(ho_cup<=d[i])
        {
            hi++;
            ho_cup=0;
        }
        else
        {
            ho++;
            ho_cup-=d[i];
        }
        ho_cup+=t;

    }
    return ho>hi;

}
int BinarySearch(int l,int r)
{
    if(l==r-1)
        return r;
    int mid=(l+r)/2;
    if(f(mid))
        return BinarySearch(l,mid);
    else
        return BinarySearch(mid,r);

}
int main()
{
    freopen("a.txt","r",stdin);
    scanf("%d%d",&n,&k);
    for(int i=0;i<n;i++)
        scanf("%d",d+i);
    printf("%d",BinarySearch(0,k+1));
    return 0;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章