波松分酒问题代码

参考文章:http://www.cnblogs.com/heaad/archive/2010/11/22/1884658.html

有一个12品脱的酒瓶,里面装满葡萄酒,另有8品脱和5品脱的瓶子各一个。问如何从中分出6品脱的酒出来?

分析: 

假有有大中小三个酒瓶,容量分别为12、8、5。如何能分出6品脱的酒?

各个酒瓶中,初始酒量为{12,0,0},不管怎样倒,如果能倒成{6,6,0},那么这个问题就解决了。我们假设{12,0,0}是一个状态,{6,6,0}是一个状态。

倒酒的动作是有限的,可以大瓶倒入小瓶、小瓶也可以倒入大瓶,为了倒酒动作不重复,我们只选取三个动作:{"大瓶倒入中瓶","中瓶倒入小瓶","小瓶倒入大瓶"}。

现在的问题就是{12,0,0}经过N次动作变成{6,6,0},因此这就变成一个搜索问题。

下面用深度优先搜索方法编写,代码如下:

 1 #include <stdio.h>
 2 struct state
 3 {
 4     int L;        //large        大瓶 
 5     int M;        //medium    中瓶 
 6     int S;        //small        小瓶 
 7 };
 8 
 9 struct state stt={12,0,0};    //酒瓶中的酒量 
10 struct state s_record[20];    //记录每次动作后酒瓶中的酒量 
11 
12 struct state bottle={12,8,5};//酒瓶容量 
13  
14 char *action[]={"大瓶倒入中瓶","中瓶倒入小瓶","小瓶全部倒入大瓶"}; //三个动作 
15 int a_record[20];    //记录每一次选择的动作 
16 
17 //三种动作0 1 2,此函数根据动作计算生成的状态,
18 //并判断此动作是否可以执行,如不能执行则返回0,执行成功则返回1 
19 int rule(int i,int step)
20 {
21     struct state temp;
22     int j;
23     
24     temp=stt;
25     
26     if(i==0)    //大瓶倒入中瓶(要么倒满中瓶,要么倒空大瓶,实际上总是能倒满中瓶) 
27     {
28         if(stt.M==bottle.M)return 0;        //如果中瓶本来是满的,则此动作不能执行
29         if(stt.L+stt.M<bottle.M)return 0;    //如果大瓶与中瓶加起来不足中瓶的容量,则此动作不执行 
30         temp.L=stt.L-(bottle.M-stt.M);        //大瓶减去中瓶空的容量 
31         temp.M=bottle.M;                        //中瓶倒满 
32     }
33     if(i==1)    //中瓶倒入小瓶(要么倒满小瓶,要么倒空中瓶)
34     {
35         if(stt.S==bottle.S)return 0;        //如果小瓶是满的,不倒 
36         if(stt.M==0)return 0;                //如果中瓶是空的,不倒
37         if(stt.M+stt.S<bottle.S)            //如果中瓶与小瓶加起来不足小瓶的容量,则倒空中瓶 
38         {
39             temp.S=stt.M+stt.S;
40             temp.M=0;
41         }
42         else                                //否则倒满小瓶 
43         { 
44             temp.M=stt.M-(bottle.S-stt.S);
45              temp.S=bottle.S;
46         }
47     }
48     if(i==2)    //小瓶全部倒入大瓶 
49     {
50         //只有一种情况,当小瓶满了的时候才能倒入大瓶
51         if(stt.S<bottle.S)return 0;
52         
53         temp.L=stt.L+stt.S;
54         temp.S=0;
55     }
56     for(j=0;j<step;j++)
57         if(s_record[j].L==temp.L&&s_record[j].M==temp.M&&s_record[j].S==temp.S)
58             return 0;
59     stt=temp;
60     return 1;        
61 }
62 
63 void fun(int step)
64 {
65     if(stt.M==6&&stt.L==6)
66     {
67         int i;
68         for(i=0;i<step;i++)
69         {
70             printf("%-20s\t%3d%3d%3d\n",action[a_record[i]],s_record[i].L,s_record[i].M,s_record[i].S);
71         }    
72         printf("\n\n");
73     }
74     else 
75     {
76         int i;
77         for(i=0;i<3;i++)
78         {
79             if(rule(i,step))
80             {
81                 a_record[step]=i;        //记录本次动作 
82                 s_record[step]=stt;        //记录执行动作后的状态 
83                 fun(step+1);
84             }
85         }
86     }
87 }
88 int main()
89 {
90     fun(0);
91     return 0;
92 }

 

posted @ 2016-04-13 10:07  地中生木  阅读(695)  评论(0)    收藏  举报