问题如下:
黑马程序员训练营入学考试题
10、 28人买可乐喝,3个可乐瓶盖可以换一瓶可乐,那么要买多少瓶可乐,够28人喝?假如是50人,又需要买多少瓶可乐?(需写出分析思路)
我的思路1: --------结果思维
利用逆向思维和全局思维,假如28个都喝到了可乐,那么会有28个盖子,就可以兑换28/3 = 9(截断,只能买少不能买多)瓶可乐,那么一共就得买28-9 = 19瓶可乐才够28个人喝。
同理:50个人喝可乐,需要50-50/3 =50-16= 34瓶可乐
当然,这个数学计算写代码的话太easy了,我就不演示了。
我的思路2:
利用多线程的等待唤醒机制,代码如下:
/*
黑马程序员训练营入学考试题
10、 28人买可乐喝,3个可乐瓶盖可以换一瓶可乐,那么要买多少瓶可乐,够28人喝?假如是50人,又需要买多少瓶可乐?(需写出分析思路)
利用逆向思维来想的话:
28个人如果都喝到了可乐,那么会有28个瓶盖,就可以换取28/3 = 9瓶可乐。那么一共需要买28-28/3 = 19瓶可乐才够喝。
同理,50个人需要买50-50/3 = 34瓶可乐。
解题思路:
看这个题的模型有点像生产者与消费者的例子
定义两个线程
一个线程买可乐:
一个线程收集瓶子兑换可乐
*/
//为了突出重点,下面的成员变量就不用private私有化了。
import java.util.concurrent.locks.*;
class Kele
{
int need = 0; //需要喝可乐的人数
int buyCount = 0; //已经买到的可乐个数
int returnCount = 0; //通过盖子兑换回来的可乐个数
int drokedCount = 0; //喝掉的可乐个数,也就是盖子的个数。
boolean flag = false; //记录是否每个人都喝到可乐了。
boolean flagBuyed = false; //切换买可乐和换盖子的线程
//定义一个锁
private Lock lock = new ReentrantLock();
private Condition con_buy = lock.newCondition();
private Condition con_col = lock.newCondition();
public Kele(int need)
{
this.need = need;
}
public void buy() //买可乐
{
lock.lock();
try
{
if(flagBuyed) //如果买了一瓶可乐的话,就得重新计算剩余的瓶盖是否能够3兑换一瓶可乐。
{
try
{
con_buy.await();
}
catch (Exception e)
{
throw new RuntimeException("等待异常");
}
}
buyCount++; //买1瓶可乐给1人喝
drokedCount++; //同时买1瓶可乐会多出1盖子
flagBuyed = true;
con_col.signal();
}
catch(Exception e)
{
throw new RuntimeException(e.toString());
}
finally
{
lock.unlock();
}
}
public void col() //兑换盖子
{
lock.lock();
try
{
if(!flagBuyed)
{
try
{
con_col.await();
}
catch (Exception e)
{
throw new RuntimeException("等待异常");
}
}
//方式1-按照常规地来推理(不知道为什么这种方式对于28结果是20,多了一个;而对于50,结果是34,刚好。
//if(drokedCount == 3) //如果收集的盖子数量达到3个,就换1瓶可乐,同时盖子就剩下一个了。
//{
//returnCount++;
//drokedCount = 1; //虽然每次要清零,但同时会多出一个盖子。
//}
//方式2-将条件转换一下:3个盖子换一瓶可乐,相当于2个盖子换一瓶无盖的可乐
if(drokedCount == 2) //如果收集的盖子数量达到3个,就换1瓶可乐,同时盖子就剩下一个了。
{
returnCount++;
drokedCount = 0; //只是会多出一瓶可乐,但是盖子没有计数。
}
flagBuyed = false;
con_buy.signal();
}
catch(Exception e)
{
throw new RuntimeException(e.toString());
}
finally
{
lock.unlock();
}
}
}
class Buyer implements Runnable //买可乐的线程
{
Kele k;
public Buyer(Kele k)
{
this.k = k;
}
public void run() //买可乐
{
while(k.buyCount + k.returnCount < k.need)
{
k.buy();
}
k.flag = true;
}
}
class Collector implements Runnable //收集盖子的线程,返回可乐。
{
Kele k;
public Collector(Kele k)
{
this.k = k;
}
public void run()
{
while(k.buyCount + k.returnCount < k.need)
{
k.col();
}
k.flag = true;
}
}
class RXtest10
{
public static void main(String[] args) throws Exception
{
Kele res = new Kele(50);
new Thread(new Buyer(res)).start();
new Thread(new Collector(res)).start();
while(!res.flag){} //两个子线程没有结束,坚决不让主线程输出。相当于让主线程阻塞了。相当让两个子线程join了,同时它们又可以交替执行。防止子线程还没有标记标签主线程就开始输出了。
System.out.println(res.need + "个人需要买" + res.buyCount + "瓶可乐");
}
}
关于这道题,百度一下,有很多的解法可供参考,其一 喝可乐的问题
咱们西313的韩淼同学的答案:
int person = 28; //总人数
int kele = 0; //需要买的可乐的个数
int cups = 0; //兑换的盖子的个数
for(int i = 1; i <= person; i++) //数组模拟喝可乐的人
{
if(cups==3) //盖子到了3个
{
cups=1;
kele++;
}else{ //盖子没有达到3个,买一瓶可乐,多出1个盖子。
kele++;
cups++;
}
}
//最后得到kele即是要求的结果
转载于:https://blog.51cto.com/4259297/1663206