Introduction to Dichotomy - POJ1064, POJ2456, POJ3111

Dichotomy, as its name implies, divides the solution interval into two parts from the middle to find the optimal solution interval, and achieves the goal of fast approaching the optimal solution by continuously reducing the solution interval by half.
Usually, mid=(L+R)/2 is chosen between the left and right boundaries of L and R, and the left or right intervals are determined by satisfying the requirements of the problem at mid, and the intervals are reduced by L=mid or R=mid.
The end condition of dichotomy can be achieved by the difference between left and right boundaries such as while (R-L > 0.01) or by a specified number of cycles for (int I = 0; I < 100; I +). It should be noted that the error of floating point intervals may lead to the use of left and right boundaries to determine the end of dichotomy into a dead cycle, so different problems need to be analyzed and made different choices.
Topics such as POJ1064, POJ2456 and POJ3111 are all searching for the optimal value satisfying the conditions by dichotomy.

Cable master POJ - 1064

The n-segment rope is cut out of k-segment with the same length, and can not be spliced together, so the feasible maximum length can be obtained.
The answer is approached by dichotomy, and the O (n) time is used to judge whether it is feasible or not.

#include<iostream>
#include<string>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<cstring>
using namespace std;
int n, k;
double len[10005];
double star,endd;
int main(){
    while (~scanf("%d%d", &n, &k)){
        star = endd = 0;
        for (int i = 0; i < n; i++){ scanf("%lf", &len[i]); endd += len[i]; }
        endd *= 2;
        double mid;
        int num;
        for (int i = 0; i <= 100;i++){
            mid = (star + endd) / 2;
            num = 0;
            for (int i = 0; i < n; i++){
                num += int(len[i] / mid);
            }
            if (num >= k){ star = mid; }
            else{ endd = mid; }
        }
        printf("%.2lf\n", floor(endd*100)/100);
    }

    return 0;
}

Aggressive cows POJ - 2456

Given the coordinates of n cowhouses, it is required to arrange k cows to find the maximum minimum distance between adjacent cows. Similar to the above, the idea is to change the interval into integer interval, which can also be used to judge whether the condition is satisfied or not in O (n).

#include<iostream>
#include<string>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<cstring>
using namespace std;
int n, k;
int p[100005];
int star,endd;
int main(){
    while (~scanf("%d%d", &n, &k)){
        star = 0;
        endd = 0x3f3f3f;
        for (int i = 0; i < n; i++){ scanf("%d", &p[i]); }
        sort(p, p + n);
        int mid;
        int num,cnt;
        while(endd-star>1){
            mid = (star + endd) / 2;
            num = 1;
            cnt = p[0];
            for (int i = 1; i < n; i++){
                if ((p[i] - cnt) >= mid){
                    num++;
                    cnt = p[i];
                }
                if (num == k)break;
            }
            if (num >= k){ star = mid; }
            else{ endd = mid; }
        }
        printf("%d\n", star);
    }
    return 0;
}

K Best POJ - 3111

Select k items from n items to maximize the total value/weight.
Easy to prove greed is wrong, thinking is dichotomy answer, dichotomy judgment requires the selection of k items
Make (v1+v2 +... + vk)/(w1+w2+... +wk) >=mid.
Then (v1+v2 +... + vk) - (w1+w2 +... + W k) * mid >= 0; so long as you greedily choose the maximum K items of v-w*mid.

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<math.h>
using namespace std;
int n, k;
int v[100005], w[100005];
struct pp{
    int num;
    double v;
}p[100005];
bool cmp(pp a, pp b){
    return a.v > b.v;
}
int main(){
    while (~scanf("%d%d", &n, &k)){
        for (int i = 0; i < n; i++){
            scanf("%d%d", &v[i], &w[i]);
        }
        double beg=0, endd=0x3f3f3f, mid;
        for (int i = 0; i < 50; i++){
            mid = (beg + endd) / 2;
            for (int i = 0; i < n; i++){
                p[i].num = i + 1; p[i].v = double(v[i]) - w[i] * mid;
            }
            sort(p, p + n, cmp);
            double total = 0;
            for (int i = 0; i < k; i++){ total += p[i].v; }
            if (total >= 0){ beg = mid; }
            else{ endd = mid; }
        }
        for (int i = 0; i < k; i++){
            printf("%d", p[i].num);
            if (i < k - 1){ printf(" "); }
        }
        printf("\n");
    }
    return 0;
}

If there are any mistakes or shortcomings, please exchange corrections.

Posted by t2birkey on Mon, 25 Mar 2019 22:36:28 -0700