CodeVS1725 探險 【二分答案】【貪心】
阿新 • • 發佈:2018-12-24
【題目描述】
有編號為1至n的n個同學一起去探險,現在把他們分成k個小組,每個小組完成一項探險任務。分組時,如果第i人與第j人分在同一組(i < j),則他們之間的所有人(第i+1,i+2,…,j-1個)也必須在同一個小組中。
一個小組內所有人的體力和越小,途中可能越危險。為了確保每個同學的安全,要求分組時,使得所有小組中,體力和最小的那個小組的所有人的體力和儘量大。
依次告訴你每個人的體力,如何分組呢?
【題解】
首先這個題CodeVS沒有給資料範圍,我查了一下,才知道是1≤n≤30000,1≤k≤1000, k≤n,每個人的體力值不大於10000。
這個題的意思是,要你在所有可能的分法中找出一種情況,使得最弱的那個組的體力和最大。很顯然,我們是希望我們求的答案在這一組最小的情況下最大,如果我們列舉答案的話,這個答案應該是從大到小的,而列舉的思路就讓我們想到了用二分答案。
想到了二分就要想怎麼寫check。很顯然,我們想讓其他的分組在每個組都大於列舉的那個答案的情況下還要滿足分成k組的情況。這個是比較好寫的。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=30000;
int w[N+5];
int n,k;
bool check(int x)
{
int sum=0,num=0;//表示體力和和組數
for(int i=1;i<=n;i++)
{
if(sum<x)sum+=w[i];
else
{
num++;
sum=w[i];
if (num>=k)return true;
}
}
if(sum>=x)num++;//可能會在加上w[n]的時候少算一組
if(num>=k)return true;
else return false;
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
int lf=0,rg=1e9+5;
while(rg-1>lf)
{
int mid=(lf+rg)>>1;
if(check(mid))lf=mid;
else rg=mid;
}
printf("%d",lf);
return 0;
}