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

ZOJ——Copying Books 最大值最小化問題 (貪心 + 二分)

題目連結:

#include <cstdio>
#include <cmath>
#include<vector>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stack>
#include<string>
#include<iostream>
#include<set>
#include<vector>
using namespace std;
#define maxn 505
int m,k;
long long arr[maxn],sum,Min,ans;
bool vis[maxn];
int divide(long long M)
{
    memset(vis,0,sizeof(vis));
    int cnt=0;
    int pos=m-1;
    while(pos>=0)
    {
        long long sum=0;
        bool ok=true;
        while(pos>=0&&sum+arr[pos]<=M)
        {
            ok=false;
            sum+=arr[pos];
            --pos;
        }
        if(ok)
        {
            return k+1;
        }
        if(pos>=0)
        vis[pos]=true;//這裡想了hin久,就是如果和不超過M,但是k還少的話,下一個函式就要加上/
        ++cnt;
    }
    return cnt;
}
long long binary()
{
    long long left=Min,right=sum,mid;
    while(left<right)
    {
        mid=(left+right)/2;
        if(divide(mid)<=k)
            right=mid;
        else
            left=mid+1;
    }
    return right;
}
void output()
{
    int cnt=divide(ans);
    for(int i=0;i<m-1&&cnt<k;++i)
    {
        if(!vis[i])
        {
            vis[i]=true;
            ++cnt;
        }
    }
    for(int i=0;i<m;++i)
    {
        if(i)
            printf(" %lld",arr[i]);
        else
            printf("%lld",arr[i]);
        if(vis[i])
            printf(" /");
    }
    puts("");
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&m,&k);
        sum=0;
        Min=0;
        for(int i=0;i<m;i++)
        {
            scanf("%lld",&arr[i]);
            sum+=arr[i];
            if(arr[i]>Min)
                Min=arr[i];
        }
        ans=binary();
        output();
    }
    return 0;
}