//------------------------------------------------------------------------
//大小油壶问题
//油店招工,出题考试:有一缸油,但仅有两个油壶,大的可装11升,小的可装7升,
//现在要按1升油分装,怎么分呢?
//思路:如果到了某一步,油壶为空,可以再取油;油壶为满可以倒掉,也可以转到另一个壶中
#include <stdio.h>
#include <windows.h>
#define BIG 11 //大壶容量
#define SMALL 07 //小壶容量
#define RESULT 01 //要求的结果RESULT<BIG
#define MAX_STEPS 100 //定义最大步数,避免无解时无限循环
//其实非递归更加有效
//使用这两个数组只是为了知道中间的过程
int Big[MAX_STEPS]; //记录每一步的大壶中的油
int Small[MAX_STEPS]; //记录每一步的小壶中的油
int bottle(int n)
{ if(n>=MAX_STEPS)
return false; //未找到解,试试把MAX_STEPS定义为更加大的值
if(Big[n]==RESULT || Small[n]==RESULT)
return n; //已经找到解,返回解的步数
if(Small[n]==0)//小壶是空的
{ Small[n+1]=SMALL;//小壶加满
Big[n+1]=Big[n];//大壶不变
} else if(Big[n]<BIG)//大壶没有满
{ int x=min(BIG-Big[n],Small[n]);//大壶是有容量限制的
Small[n+1]=Small[n]-x;//小壶->大壶
Big[n+1]=Big[n]+x;//
} else//大壶满了
{ Small[n+1]=Small[n];//小壶不变
Big[n+1]=0;//大壶清空
}
return bottle(n+1);//简单递归
};
void test()
{ Big[0]=0,Small[0]=0;//设定初始状态
int r=bottle(0);
for(int i=0;i<=r;++i)
{ printf("第%2d步:大壶%2d,小壶%2d/n",i,Big[i],Small[i]);
}
};
//注意:结果并非是最优解,而是贪婪解
//因为解法中只是将小壶作为主动壶,而大壶作为辅助壶,也就是小壶可直接取油,而大壶
//总是从小壶中取油,事实上大壶也可直接取油,将算法略作调整即可
//更简单的,将BIG和SMALL定义对调即可得到以大壶为主动壶时的解。
//看起来是有点别扭,似乎定义成FIRST和SECOND更恰当,这个就留给你去做吧。
//深入一下
//问题实际上就是求二元一次方程a*x-b*y=c的整数解,其中a,b为两个油壶的容量,c是需要的容量
//x,y就是要求的未知数,x代表倒进的次数,y代表倒出的次数,x>=0,y>=0
//a,b设置不同结果当然不同,求出x,y就知道具体过程了
//如果是有三个油壶
//问题实际上就是求三元一次方程a*x+b*y+c*z=d的整数解
//不过这里x,y,z可以是负整数了,为正代表倒进,为负代表倒出
//类似可解决更多个油壶的问题