问题:现在有三个木桶容量分别为8,5,3升,最初容量为8升的木桶内装满了水,另外两个木桶内为空。三个木桶都没有体积刻度,现在需要将大水桶的8升水等分成两份,每份4升水。列出所有可行的方案。(附不能借助除这三个木桶的其他桶接水)
思路分析:这个问题的思路和农夫过河问题的思路基本类似,只是问题的模型改变了,可以参考另一篇文章求解农夫过河问题
C语言代码:
#include<stdio.h>
#define maxsize 100
typedef struct{ //定义3个木桶组的结构体
int capability[3]; //记录容量
int contain[3]; //记录容积
}group;
int judge(group route[maxsize],int location,group newone) //判断新状态在该路径上是否产生重复
{ //有重复返回1,没有重复返回0
int i;
for(i=0;i<=location;i++)
{
if(route[i].contain[0]==newone.contain[0]&&route[i].contain[1]==newone.contain[1]&&route[i].contain[2]==newone.contain[2])
{
return 1;
}
}
return 0;
}
void print(group route[maxsize],int location) //输出某路径记录的方案
{
int i;
for(i=0;i<=location;i++)
{
printf("%d %d %d\n",route[i].contain[0],route[i].contain[1],route[i].contain[2]);
}
printf("\n");
}
void process(group someone,group route[maxsize],int location) //算法核心,利用深度优先搜索进行遍历,找到满足条件的路径就立刻输出
{
if(someone.contain[0]==4&&someone.contain[1]==4) //如果把8升水平分完成
{
print(route,location); //输出该路径的方案
}
else
{
int i,s,e,o;
for(i=0;i<=5;i++) //倒水的6种方案
{
switch(i)
{
case 0:
s=0;e=1;o=2;break; //第一个桶往第二个桶里倒
case 1:
s=0;e=2;o=1;break; //第一个桶往第三个桶里倒
case 2:
s=1;e=0;o=2;break; //第二个桶往第一个桶里倒
case 3:
s=1;e=2;o=0;break; //第二个桶往第三个桶里倒
case 4:
s=2;e=0;o=1;break; //第三个桶往第一个桶里倒
case 5:
s=2;e=1;o=0;break; //第三个桶往第二个桶里倒
}
if(someone.contain[s]!=0) //如果要出水的桶不为空
{
if(someone.contain[e]<someone.capability[e]) //如果要接水的桶还有剩余空间
{
group newone=someone; //生成一个新的状态
group newroute[maxsize]; //生成一个新的路径
int i;
for(i=0;i<=location;i++) //新的路径先把原来的路径拷贝进来
{
newroute[i]=route[i];
}
if(someone.contain[s]<=(someone.capability[e]-someone.contain[e])) //如果出水的桶需要把水全部倒入接水的桶中
{
newone.contain[s]=0;
newone.contain[e]=someone.contain[s]+someone.contain[e];
newone.contain[o]=someone.contain[o];
if(judge(route,location,newone)==0) //如果新状态没有重复过
{
newroute[location+1]=newone; //把新状态记录进新路径中
process(newone,newroute,location+1); //从新状态即新路径出发继续深度优先搜索下去
}
}
else //如果出水的桶只能把部分水倒入接水的桶中
{
newone.contain[s]=someone.contain[s]-(someone.capability[e]-someone.contain[e]);
newone.contain[e]=someone.capability[e];
newone.contain[o]=someone.contain[o];
if(judge(route,location,newone)==0) //如果新状态没有重复过
{
newroute[location+1]=newone; //把新状态记录进新路径中
process(newone,newroute,location+1); //从新状态即新路径出发继续深度优先搜索下去
}
}
}
}
}
}
}
int main()
{
group origin;
origin.capability[0]=8;
origin.capability[1]=5;
origin.capability[2]=3;
origin.contain[0]=8;
origin.contain[1]=0;
origin.contain[2]=0; //初始化木桶组的状态
group route[maxsize];
int location=0;
route[location]=origin; //初始化路径,location记录路径最新状态的位置(下标)
process(origin,route,location); //从初始状态出发查找所有可行方案
}
代码运行结果:
8 0 0
3 5 0
0 5 3
5 0 3
5 3 0
2 3 3
2 5 1
7 0 1
7 1 0
4 1 3
4 4 0
8 0 0
3 5 0
3 2 3
0 5 3
5 0 3
5 3 0
2 3 3
2 5 1
7 0 1
7 1 0
4 1 3
4 4 0
8 0 0
3 5 0
3 2 3
5 0 3
5 3 0
2 3 3
2 5 1
7 0 1
7 1 0
4 1 3
4 4 0
8 0 0
3 5 0
3 2 3
6 2 0
6 0 2
1 5 2
0 5 3
5 0 3
5 3 0
2 3 3
2 5 1
7 0 1
7 1 0
4 1 3
4 4 0
8 0 0
3 5 0
3 2 3
6 2 0
6 0 2
1 5 2
1 4 3
0 5 3
5 0 3
5 3 0
2 3 3
2 5 1
7 0 1
7 1 0
4 1 3
4 4 0
8 0 0
3 5 0
3 2 3
6 2 0
6 0 2
1 5 2
1 4 3
5 0 3
5 3 0
2 3 3
2 5 1
7 0 1
7 1 0
4 1 3
4 4 0
8 0 0
3 5 0
3 2 3
6 2 0
6 0 2
1 5 2
1 4 3
4 4 0
8 0 0
3 5 0
3 2 3
6 2 0
6 0 2
5 0 3
5 3 0
2 3 3
2 5 1
7 0 1
7 1 0
4 1 3
4 4 0
8 0 0
5 0 3
0 5 3
3 5 0
3 2 3
6 2 0
6 0 2
1 5 2
1 4 3
4 4 0
8 0 0
5 0 3
5 3 0
3 5 0
3 2 3
6 2 0
6 0 2
1 5 2
1 4 3
4 4 0
8 0 0
5 0 3
5 3 0
2 3 3
0 5 3
3 5 0
3 2 3
6 2 0
6 0 2
1 5 2
1 4 3
4 4 0
8 0 0
5 0 3
5 3 0
2 3 3
2 5 1
0 5 3
3 5 0
3 2 3
6 2 0
6 0 2
1 5 2
1 4 3
4 4 0
8 0 0
5 0 3
5 3 0
2 3 3
2 5 1
7 0 1
7 1 0
3 5 0
3 2 3
6 2 0
6 0 2
1 5 2
1 4 3
4 4 0
8 0 0
5 0 3
5 3 0
2 3 3
2 5 1
7 0 1
7 1 0
4 1 3
0 5 3
3 5 0
3 2 3
6 2 0
6 0 2
1 5 2
1 4 3
4 4 0
8 0 0
5 0 3
5 3 0
2 3 3
2 5 1
7 0 1
7 1 0
4 1 3
4 4 0
8 0 0
5 0 3
5 3 0
2 3 3
2 5 1
3 5 0
3 2 3
6 2 0
6 0 2
1 5 2
1 4 3
4 4 0
总共有16种可行的方案,其中最快,代价最小的方案是:
8 0 0
3 5 0
3 2 3
6 2 0
6 0 2
1 5 2
1 4 3
4 4 0