问题描述
小Q的父母要出差N天,走之前给小Q留下了M块奶糖。小Q决定每天吃的奶糖数量不少于前一天吃的一半,但是他又不想在父母回来之前的某一天没有奶糖吃,请问他第一天最多能吃多少块奶糖?
输入描述:
每个输入包含一个测试用例。
每个测试用例的第一行包含两个正整数,表示父母出差的天数N(N<=50000)和巧克力的数量M(N<=M<=100000)。
输出描述:
输出一个数表示小Q第一天最多能吃多少块奶糖。
示例1
输入
3 7
输出
4
思想:二分的思想
上一下代码,具体的思路注释在代码里了,注意while层循环和for层循环的不同作用,while层循环主要是用来规划吃糖的计划的,for层循环来验证这样的计划是否可行,如果不行,那么再进while循环里二分规划下一个吃糖计划。
public class 贪吃的小Q {
public static void main(String[] args) {
int n,m,temp,now,mid;
boolean flag;
Scanner scanner = new Scanner(System.in);
//父母的出差天数n
n=scanner.nextInt();
//一共有几块奶糖,奶糖数m
m=scanner.nextInt();
int l=1,r=m;
while(l!=r)
{ //如果够吃,那么flag就是true
flag=true;
//利用二分查找的思想来判断第一天最多能吃多少块
mid=(l+r+1)/2;
//temp保存的是奶糖总数m,在while这层循环里是不变的
temp=m;
//now可以理解为一次吃几个糖
now=mid;
//这个for循环很关键
//注意条件j<n,n是父母出差的天数,这个for循环存在的意义就是看在父母回来之前怎么吃不会有一天吃不上
//如果有一天吃不上了,也就意味着 当前剩余的奶糖数 < 按计划要吃的奶糖数了(temp<now)
//这时就意味着第一天就吃多了,这个吃糖方案是不对的,需要break出for循环 重新规划 第一天吃多少糖
//如果for能跑完,没有break,那么说明这样的吃糖方案是正确的,flag将会是true
//mid保存的就还是成功方案的第一天吃的糖数,下面if语句中l=mid赋值后,输出l就是问题答案了。
for(int j=0; j<n; j++)
{
//如果不够吃,跳出for循环,在while循环里从第一天吃多少开始重新规划方案。
if(temp<now)
{
flag=false;
break;
}
//此处的temp会根据前一天吃掉的奶糖数量更新
// 比如一共有7块糖,第一天吃了4块,第二天就剩temp=temp-now=3块糖了
temp-=now;
//now就是按 每天吃的巧克力数量不少于前一天吃的一半 这样赋值的
now=(now+1)/2;
}
if(flag)
l=mid;
else
//这里的r就是重新规划第一天吃多少糖的体现,也是二分思想的体现
//因为r被赋的初值是m,也就是奶糖的总数,这时r=mid-1意为着第一次吃的奶糖数 折半
r=mid-1;
//r被重新赋值后,判断一下是否l!=r,如果
}
System.out.println("小Q第一天最多能吃"+l+"个奶糖");
}
}
大家可以debug一遍看一看,就好理解多了。