一道面试题——四人喝酒的问题
来源:互联网 发布:绿色上网软件 编辑:程序博客网 时间:2024/04/30 13:28
有a,b,c,d四个人,现在有X,Y,Z三个不规则酒杯,X,Y容量为8两,现在已装满酒,Z容量为3两,为空杯.现在要求四个人每人都能平均喝到4两酒,请说出该怎么喝?写出算法,并打印出每步X,Y,Z杯内的酒多少和四个人每人所喝的酒?
这道题的来源不可考。在网上搜《编程之美》烙饼问题的相关资料的时候看到了这道题,之前没接触过算法,手算想了一会儿居然没有算出来~想了大概一天的时间,终于把代码搞定了。
此题类似于《编程之美》中烙饼问题所采用的剪枝+分支定界,关键是对问题过程的处理。只要把问题过程理清,找好边界条件和退出条件,问题自然迎刃而解。我们先找边界条件,显然
a)每个人都喝到4两酒肯定是程序执行完成的条件,
b)为了避免重复进入之前某种状态,我们需要判断当前状态是否出现过。
再明确我们倒酒的过程,这里只需要弄清可以倒酒的状态分类。首先,对X、Y、Z三个酒杯的状态和a、b、c、d四个人喝酒的状态要区别对待:
a)当且仅当某人当前的酒量和酒杯中酒量之和小于等于4,此人才能喝酒。显然,这才是最终可以满足边界条件a的过程
b)在三个酒杯之间互相倒酒,要注意每个酒杯都不能溢出
c)如果此状态之前出现过,说明这种状态之下走不通,就没有必要在此状态之下继续进行。另外,X和Y酒杯由于容量一样,在其他状态相同的情况下,可视为相同的状态。
理解了这些,写出代码就比较容易。
/* 有a,b,c,d四个人,现在有X,Y,Z三个不规则酒杯,X,Y容量为8两,现在已装满酒, * Z容量为3两,为空杯.现在要求四个人每人都能平均喝到4两酒,请说出该怎么喝? * 写出算法,并打印出每步X,Y,Z杯内的酒多少和四个人每人所喝的酒? */#include <stdio.h>/* 递归调用退出条件:每人都喝到4两,或者回到中间的某个状态 */#define MAX_STATES1024/* 保存中间状态,如果是之前的某个状态就退出 */#define MAX_STEPS100/* 保存最终采用的步骤 */typedef struct{unsigned char StateArray[7];/* StateArray 0~2 represent X, Y, Z;3~6 represent A, B, C, D*/}STATE;static int StateIndex;static int PourStepState[MAX_STATES];/* 类似于栈结构,中间状态 */static int MaxSteps;static STATE PrintStepIndex[MAX_STEPS];/* 最终采用的状态 */static __inline void PrintPourSteps(STATE TempState){int i;++MaxSteps;for(i = 0; i < 7; i++){PrintStepIndex[MaxSteps].StateArray[i] = TempState.StateArray[i];}}#define STATE_EXIST1#define STATE_NOT_EXIST0static int CheckState(STATE TempState){/* 检查当前状态,如果是之前的状态则直接返回,否则保存当前状态 */int i, TempSum = 0;for(i = 0; i < 7; i++){TempSum = TempSum * 10 + TempState.StateArray[i];}for(i = StateIndex; i > 0; i--){if(TempSum == PourStepState[i])return STATE_EXIST;if(TempState.StateArray[0] == (PourStepState[i]/100000)%10 &&TempState.StateArray[1] == PourStepState[i]/1000000 &&TempSum%100000 == PourStepState[i]%100000){/* 对X和Y的状态不做区分 */return STATE_EXIST;}}PourStepState[++StateIndex] = TempSum;return STATE_NOT_EXIST;}static __inline void PourStepNext(STATE *TempState, STATE *PreState){int i;for(i = 0; i < 7; i++){TempState->StateArray[i] = PreState->StateArray[i];}return;}#define POUR_SUCCEED1#define POUR_FAIL0/* 分清处理步骤,注意顺序先尝试X,Y,Z向A,B,C,D中倒,然后进行 * X,Y,Z之间的处理,否则容易出现死循环或者中间过程过度展开 */int DoPouring(STATE PreState){inti, j;STATE TempState;for(i = 0; i <= 2; i++){for(j = 3; j < 7; j++){if(PreState.StateArray[i] + PreState.StateArray[j] <= 4 && PreState.StateArray[i]){PourStepNext(&TempState, &PreState);TempState.StateArray[j] += TempState.StateArray[i];TempState.StateArray[i] = 0;if(TempState.StateArray[3] == 4 && TempState.StateArray[4] == 4 &&TempState.StateArray[5] == 4 && TempState.StateArray[6] == 4){PrintPourSteps(TempState);return POUR_SUCCEED;}if(CheckState(TempState) == STATE_NOT_EXIST){if(DoPouring(TempState) == POUR_SUCCEED){PrintPourSteps(TempState);return POUR_SUCCEED;}}}}}if(PreState.StateArray[1] < 8 && PreState.StateArray[0])/* X --> Y */{if(PreState.StateArray[0] + PreState.StateArray[1] > 8){PourStepNext(&TempState, &PreState);TempState.StateArray[0] = TempState.StateArray[0] + TempState.StateArray[1] - 8;TempState.StateArray[1] = 8;}else{PourStepNext(&TempState, &PreState);TempState.StateArray[1] += TempState.StateArray[0];TempState.StateArray[0] = 0;}if(CheckState(TempState) == STATE_NOT_EXIST){if(DoPouring(TempState) == POUR_SUCCEED){PrintPourSteps(TempState);return POUR_SUCCEED;}}}if(PreState.StateArray[2] < 3 && PreState.StateArray[0])/* X --> Z */{if(PreState.StateArray[0] + PreState.StateArray[2] > 3){PourStepNext(&TempState, &PreState);TempState.StateArray[0] = TempState.StateArray[0] + TempState.StateArray[2] - 3;TempState.StateArray[2] = 3;}else{PourStepNext(&TempState, &PreState);TempState.StateArray[2] += TempState.StateArray[0];TempState.StateArray[0] = 0;}if(CheckState(TempState) == STATE_NOT_EXIST){if(DoPouring(TempState) == POUR_SUCCEED){PrintPourSteps(TempState);return POUR_SUCCEED;}}}if(PreState.StateArray[0] < 8 && PreState.StateArray[1])/* Y --> X */{if(PreState.StateArray[0] + PreState.StateArray[1] > 8){PourStepNext(&TempState, &PreState);TempState.StateArray[1] = TempState.StateArray[0] + TempState.StateArray[1] - 8;TempState.StateArray[0] = 3;}else{PourStepNext(&TempState, &PreState);TempState.StateArray[0] += TempState.StateArray[1];TempState.StateArray[1] = 0;}if(CheckState(TempState) == STATE_NOT_EXIST){if(DoPouring(TempState) == POUR_SUCCEED){PrintPourSteps(TempState);return POUR_SUCCEED;}}}if(PreState.StateArray[2] < 3 && PreState.StateArray[1])/* Y --> Z */{if(PreState.StateArray[1] + PreState.StateArray[2] > 3){PourStepNext(&TempState, &PreState);TempState.StateArray[1] = TempState.StateArray[1] + TempState.StateArray[2] - 3;TempState.StateArray[2] = 3;}else{PourStepNext(&TempState, &PreState);TempState.StateArray[2] += TempState.StateArray[1];TempState.StateArray[1] = 0;}if(CheckState(TempState) == STATE_NOT_EXIST){if(DoPouring(TempState) == POUR_SUCCEED){PrintPourSteps(TempState);return POUR_SUCCEED;}}}if(PreState.StateArray[0] < 8 && PreState.StateArray[2])/* Z --> X */{if(PreState.StateArray[0] + PreState.StateArray[2] > 8){PourStepNext(&TempState, &PreState);TempState.StateArray[2] = TempState.StateArray[0] + TempState.StateArray[2] - 8;TempState.StateArray[0] = 8;}else{PourStepNext(&TempState, &PreState);TempState.StateArray[0] += TempState.StateArray[2];TempState.StateArray[2] = 0;}if(CheckState(TempState) == STATE_NOT_EXIST){if(DoPouring(TempState) == POUR_SUCCEED){PrintPourSteps(TempState);return POUR_SUCCEED;}}}if(PreState.StateArray[1] < 8 && PreState.StateArray[2])/* Z --> Y */{if(PreState.StateArray[1] + PreState.StateArray[2] > 8){PourStepNext(&TempState, &PreState);TempState.StateArray[2] = TempState.StateArray[1] + TempState.StateArray[2] - 8;TempState.StateArray[1] = 8;}else{PourStepNext(&TempState, &PreState);TempState.StateArray[1] += TempState.StateArray[2];TempState.StateArray[2] = 0;}if(CheckState(TempState) == STATE_NOT_EXIST){if(DoPouring(TempState) == POUR_SUCCEED){PrintPourSteps(TempState);return POUR_SUCCEED;}}}return POUR_FAIL;}int main(){int i, j;STATE OriginalState;StateIndex = 0;MaxSteps = 0;for(i = 0; i < MAX_STATES; i++)PourStepState[i] = 0;OriginalState.StateArray[0] = 8;OriginalState.StateArray[1] = 8;for(i = 2; i < 7; i++)OriginalState.StateArray[i] = 0;DoPouring(OriginalState);printf("\tX\tY\tZ\tA\tB\tC\tD\nSTATE:");for(j = 0; j < 7; j++){printf("\t%d", OriginalState.StateArray[j]);}printf("\n");for(i = MaxSteps; i > 0; i--){printf("STATE:");for(j = 0; j < 7; j++)printf("\t%d", PrintStepIndex[i].StateArray[j]);printf("\n");}printf("Total steps: %d.\ndone.\n", MaxSteps);return 0;}
- 一道面试题——四人喝酒的问题
- 汽车加油问题——一道迷惑的面试题
- 一道有趣的面试题——扔鸡蛋问题
- 一道面试题:关于fork的问题
- 一道C语言面试题——邮票组合问题
- 一道有趣的面试题————待解决的问题
- 一道C语言面试题——大数相乘的问题
- 一道面试题:赛马问题
- google一道面试题的扩展——智力挑战
- 一道数据库面试题—更新
- JVM(四)—一道面试题搞懂JVM类加载机制
- 每天一道面试题(四)
- 一道简单的百度面试题遇到的问题
- 一道微软面试题的解答【镜子问题】
- 从微软的一道面试题谈问题解决之道
- 一道华为面试题的分析(约瑟夫问题)
- 一道经典的面试题--12小球称重问题
- 百度面试题一道2(著名的蚂蚁问题)
- DrawIndexedPrimitive函数的详细解释
- 会讲的六十八个故事
- 如何将表单数据从一页传递到另一个,通过使用 GET 和 POST 活动服务器页中
- 我们工作到底为了什么
- velocity 生成html
- 一道面试题——四人喝酒的问题
- 静态内存与动态内存
- SaaS应用的数据安全策略
- OpenGL开发环境配置
- 芯片的命名方式
- SDK兼容性的代码
- C#接口零度学习
- ObjC: 源文件的组织
- JDK 文档之 -- OutputStream 和 InputStream 的区别