问题如下:
黑马程序员训练营入学考试题
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 + "瓶可乐"); } }
关于这道题,百度一下,有很多的解法可供参考,其一 喝可乐的问题
时间: 2024-11-08 12:42:43