1. 程式人生 > >Copying Books(貪心 最大值最小化 二分)

Copying Books(貪心 最大值最小化 二分)

題目描述開頭一大堆屁話,我還仔細看了半天。。其實就最後2句管用。意思就是給出n本書然後要分成k份,每份總頁數的最大值要最小。問你分配方案,如果最小值相同情況下有多種分配方案,輸出前面份數小的,就像字典序輸出從小到大一樣的意思。

這裡用到貪心的方法,定義f(x)為真的條件是滿足x為最大值使n本書分成k份,那麼就是求x的最小值。如何確定這個x就是用的二分法,x一定大於0小於所有值的合,不斷的二分再判斷是否成立,成立就取左半邊,不成立說明太小了就取右半邊,寫的時候還是沒有把二分法理解透徹,我還怕會丟失那個值還特意去儲存,事實上二分法最後結束得出來的x或y(二個數是相等的)就是每份的最大值。而如何確定這個最大值是否成立就是用貪心的方法,儘量的往右邊拓展直到大於最大值的前一個為止。如果份數還沒分完就到最後一個了,那就肯定是成立的。反之,如果份數分完了還沒到最後一個那就是不成立。

輸出的時候還得注意,得從後往前,因為前面的份數得要小,就得從後往前貪心,還有當剩餘的跟份數一樣的時候就不能貪心了,就要每一個都要分開了。這個就自己模擬資料看吧,加一減一的都得跟前面寫的有關係。

還有兩點要特別注意, 求和的時候會超int範圍,因為一個最大可達1×10^8,而最多有500個,超過了4×10^9了。所以要用long long。還有一點是輸出的時候最後一個數字後面不能多打一個空格不然會報PE的。

AC程式碼:

#include<cstdio>
#include<ctype.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<ctime>
using namespace std;
#define NMAX 505
#define ll long long
int a[NMAX];
int ans[NMAX];
int solve(ll Max,int n,int k)
{
    int i=0,j=0,nct=0;
    ll sum=0;
    while(nct < k)
    {
        sum+=a[j];
        if(sum > Max && i == j) return 0;
        if(sum > Max)
        {
            nct++;
            i = j;
            sum = 0;
        }
        else j++;
        if(j == n) return 1;
    }
    return 0;
}

void path(ll Max,int n,int k)
{
    int nct = 0,i=n-1;
    ll sum=0;
    while(i>0)
    {
        sum+=a[i];
        if(sum > Max)
        {
            sum = 0;
            ans[i] = 1;
            nct++;
        }
        else i--;
        if(i == k-nct-2)
        {
            for(int j = 0; j <= i; j++)
                ans[j] = 1;
            break;
        }
    }
    for(int i = 0; i < n; i++)
    {
        if(i == n-1) printf("%d",a[i]);
        else printf("%d ",a[i]);
        if(ans[i]) printf("/ ");
    }
    printf("\n");
}

int main()
{
    int i,n,k,m;
    scanf("%d",&n);
    while(n--)
    {
        memset(ans,0,sizeof(ans));
        scanf("%d%d",&m,&k);
        ll sum = 0;
        for(i = 0; i < m; i++)
        {
            scanf("%d",&a[i]);
            sum += a[i];
        }
        ll x=0,y=sum,z;
        while(x<y)
        {
            z = x+(y-x)/2;
            if(solve(z,m,k))
                y = z;
            else x = z+1;
        }
        path(x,m,k);
    }
    return 0;
}