1. 程式人生 > >ACM之路(1)——對二分及三分的研究

ACM之路(1)——對二分及三分的研究

對於二分來說,個人暫且將其分為整數型和實數型。
     對整數型而言,一般問題對於(low<=high)條件的判斷取等號即可,因為在while途中查詢遇到可匹配的便break,比方說二分查詢已排序的數列。但是有些問題並不是這樣的,在此分為兩類:取最大值的min,和取最小值的max。
     對於前一種,要用<(即不斷往下推得最優解),而後一種要用<=(即不斷往上推得最優解)。同時,若對於前一種情況而言,因為要取最小的最優解,那麼即使取中的mid可以滿足條件仍要將high=mid-1以獲得更小的最優解;對max的情況也是一樣。
     下面給出兩個例子以示說明:
     min型:

Description

Farmer John is an astounding accounting wizard and has realized he might run out of money to run the farm. He has already calculated and recorded the exact amount of money (1 ≤ moneyi ≤ 10,000) that he will need to spend each day over the next N (1 ≤ N ≤ 100,000) days.

FJ wants to create a budget for a sequential set of exactly M

 (1 ≤ M ≤ N) fiscal periods called "fajomonths". Each of these fajomonths contains a set of 1 or more consecutive days. Every day is contained in exactly one fajomonth.

FJ's goal is to arrange the fajomonths so as to minimize the expenses of the fajomonth with the highest spending and thus determine his monthly spending limit.

Input

Line 1: Two space-separated integers: N and M
Lines 2.. N+1: Line i+1 contains the number of dollars Farmer John spends on the ith day

Output

Line 1: The smallest possible monthly limit Farmer John can afford to live with.

Sample Input

7 5100400300100500101400

Sample Output

500

Hint

If Farmer John schedules the months so that the first two days are a month, the third and fourth are a month, and the last three are their own months, he spends at most $500 in any month. Any other method of scheduling gives a larger minimum monthly limit. 

程式碼如下:

#include <stdio.h>

#include <string.h>

#include <algorithm>

using namespace std;

int a[100005];

int main()

{

    int n,m,mid;

    while(scanf("%d%d",&n,&m)==2)

    {

        int sum=0;

        int maxn=-1;

        int i;

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

        {

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

            if(a[i]>maxn) maxn=a[i];

            sum+=a[i];

        }

        mid=(maxn+sum)/2;

        while(maxn<sum)   //注意這裡是<!

        {

            int cnt=1;

            int s=0;

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

            {

                s+=a[i];

                if(s>mid)

                {

                    cnt++;

                    s=a[i];

                }

            }

            if(cnt<=m) sum=mid-1;

                else maxn=mid+1;

            mid=(maxn+sum)/2;

        }

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

    }

    return 0;

} 

max型:

Description

Every year the cows hold an event featuring a peculiar version of hopscotch that involves carefully jumping from rock to rock in a river. The excitement takes place on a long, straight river with a rock at the start and another rock at the end, L units away from the start (1 ≤ L ≤ 1,000,000,000). Along the river between the starting and ending rocks, N (0 ≤ N ≤ 50,000) more rocks appear, each at an integral distance Di from the start (0 < Di < L).

To play the game, each cow in turn starts at the starting rock and tries to reach the finish at the ending rock, jumping only from rock to rock. Of course, less agile cows never make it to the final rock, ending up instead in the river.

Farmer John is proud of his cows and watches this event each year. But as time goes by, he tires of watching the timid cows of the other farmers limp across the short distances between rocks placed too closely together. He plans to remove several rocks in order to increase the shortest distance a cow will have to jump to reach the end. He knows he cannot remove the starting and ending rocks, but he calculates that he has enough resources to remove up torocks (0 ≤ M ≤ N).

FJ wants to know exactly how much he can increase the shortest distance *before* he starts removing the rocks. Help Farmer John determine the greatest possible shortest distance a cow has to jump after removing the optimal set of M rocks.

Input

Line 1: Three space-separated integers: LN, and M
Lines 2.. N+1: Each line contains a single integer indicating how far some rock is away from the starting rock. No two rocks share the same position.

Output

Line 1: A single integer that is the maximum of the shortest distance a cow has to jump after removing M rocks

Sample Input

25 5 2214112117

Sample Output

4

Hint

Before removing any rocks, the shortest jump was a jump of 2 from 0 (the start) to 2. After removing the rocks at 2 and 14, the shortest required jump is a jump of 4 (from 17 to 21 or from 21 to 25).

程式碼如下:

#include<iostream>

#include<cstdlib>

#include<stdio.h>

#include<algorithm>

#include<math.h>

using namespace std;

int a[50000+5];

int main()

{

    int l,n,m;

    while(scanf("%d%d%d",&l,&n,&m)==3)

    {

        for(int i=1;i<=n;i++) scanf("%d",&a[i]);

        a[0]=0;a[n+1]=l;

        sort(a+1,a+1+n);

        int minn=a[1]-a[0],maxx=l;

        for(int i=1;i<=n+1;i++) minn=min(minn,a[i]-a[i-1]);

        int mid=(minn+maxx)>>1;

        while(minn<=maxx)  //注意這裡是<=!

        {

            int cnt=-1;

            int s=0;

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

            {

                s+=a[i]-a[i-1];

                if(s>=mid)

                {

                    cnt++;

                    s=0;

                }

            }

            if(cnt<n-m) maxx=mid-1;

                else minn=mid+1;

            mid=(minn+maxx)>>1;

        }

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

    }

}

至於證明過程還是將中間變數都printf出來看看好了,之前都想破頭腦才搞清楚的= =。 

至於實數型的二分或三分只要設一個eps即可,用<就行(因為區間變化是取mid的,所以如果相等就會一直處於那個值出不來了。)
但是有一個問題,精度的問題,如2.005用%.2f輸出是2.01,若想要結果是2.00,則可以這樣寫:
if((int)(high*1000)%10>=5) high-=0.005;
或者乘100用floor在除以100。
下面給一個例子:

Description

Farmer John has built a new long barn, with N (2 <= N <= 100,000) stalls. The stalls are located along a straight line at positions x1,...,xN (0 <= xi <= 1,000,000,000). 

His C (2 <= C <= N) cows don't like this barn layout and become aggressive towards each other once put into a stall. To prevent the cows from hurting each other, FJ want to assign the cows to the stalls, such that the minimum distance between any two of them is as large as possible. What is the largest minimum distance?

Input

* Line 1: Two space-separated integers: N and C 

* Lines 2..N+1: Line i+1 contains an integer stall location, xi

Output

* Line 1: One integer: the largest minimum distance

Sample Input

5 312849

Sample Output

3

Hint

OUTPUT DETAILS: 

FJ can put his 3 cows in the stalls at positions 1, 4 and 8, resulting in a minimum distance of 3. 

Huge input data,scanf is recommended.

程式碼如下:

 #include <stdio.h>
#include <string.h>
#include <algorithm>
#define eps 1e-9
using namespace std;

double a[10005];
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
        double sum=0;
        for(int i=1;i<=n;i++) {scanf("%lf",&a[i]);sum+=a[i];}
        sum/=k;
        double low=0,high=sum,mid=(low+high)/2;
        while(low+eps<high)
        {
            //printf(" %f %f %f\n",low,high,mid);
            int cnt=0;
            for(int i=1;i<=n;i++)
            {
                cnt+=(int)(a[i]/mid);
            }
            if(cnt>=k) low=mid;
            else high=mid;
            mid=(low+high)/2;
        }
        if((int)(high*1000)%10>=5) high-=0.005;
        printf("%.2f\n",high);

}