題目大意:
給出一些書的頁數,讓你求把這些書分成m份,其中最大的一份最小可能有多少頁數。最大值最小化問題。
分析:
屬於最大值最小化問題。要用到二分法找到可能取到的最小值,然後嘗試着把這些書分成若干份。如果有多解,輸出第一份儘可能小的,如果第一份相同,輸入第二份儘可能小的,以此類推。
1、輸入的時候要記錄最大的頁數,在二分的時候如果mid小於最大的頁數,直接l=mid+1,後面不用考慮。
2、知道了最小的可能值,分份數的時候要從後往前分,因爲這樣才能保證最優解。
3、如果分完發現份數小於要求的數量,從前往後添加‘ / ’。保證最優解。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#define pi acos(-1.0)
#define eps 1e-6
#define ll long long
using namespace std;
int main()
{
int t,n,k;
cin>>t;
int a[550];
while(t--)
{
cin>>n>>k;
ll sum=0;
int Max=0;
for(int i=0;i<n;i++)
{
cin>>a[i];
sum+=a[i];
Max=max(Max,a[i]);
}
ll l,r,mid;
l=0,r=sum;
while(l<=r)
{
mid=l+r>>1;
if(mid<Max)
{
l=mid+1;
continue;
}
int tot=1;
ll temp=0;
for(int i=0;i<n;i++)
{
temp+=a[i];
if(temp>mid)
{
tot++;
temp=a[i];
}
}
if(tot<=k)
r=mid-1;
else
l=mid+1;
}
// cout<<l<<endl;
ll temp=0;
int tot=0;
int ans[550];
memset(ans,0,sizeof(ans));
for(int i=n-1;i>=0;i--)
{
temp+=a[i];
if(temp>l)
{
tot++;
temp=a[i];
ans[i]=1;
}
}
if(tot<k-1)
{
for(int i=0;i<n;i++)
{
if(!ans[i])
{
ans[i]=1;
tot++;
if(tot==k-1)
break;
}
}
}
for(int i=0;i<n;i++)
{
if(!i)
printf("%d",a[i]);
else
printf(" %d",a[i]);
if(ans[i])
printf(" /");
}
printf("\n");
}
return 0;
}
附上幾組測試數據
10 9 3 100 200 300 400 500 600 700 800 900 5 4 100 100 100 100 100 5 1 2 2 2 2 2 6 4 1 1 1 1 1 900 5 3 2 7 3 3 5 7 3 2 2 2 1 1 1 2 5 3 1 1 1 1 10 6 3 1 2 3 3 2 1 9 3 900 800 700 600 500 400 300 200 100 4 2 9000 1 1 1 100 200 300 400 500 / 600 700 / 800 900 100 / 100 / 100 / 100 100 2 2 2 2 2 1 / 1 / 1 1 1 / 900 2 7 / 3 / 3 5 2 2 / 2 1 / 1 1 2 1 / 1 1 1 / 10 1 / 2 3 / 3 2 1 900 800 / 700 600 / 500 400 300 200 100 9000 / 1 1 1