分油问题C语言.doc
下载提示(请认真阅读)1.请仔细阅读文档,确保文档完整性,对于不预览、不比对内容而直接下载带来的问题本站不予受理。
2.下载的文档,不会出现我们的网址水印。
3、该文档所得收入(下载+内容+预览)归上传者、原创作者;如果您是本文档原作者,请点此认领!既往收益都归您。
文档包含非法信息?点此举报后获取现金奖励!
下载文档到电脑,查找使用更方便
15
积分
还剩页未读,继续阅读
关 键 词:问题
语言
资源描述:
设有大小不等的X,Y,Z三个无刻度的油桶,分别能够盛满油X,Y,Z(例如,X=8,Y=5,Z=3),并约定X> Y>Z。
初始时,仅X油桶盛满油,Y和Z油桶为空。要求程序寻找一种最少的分油步聚,在某个油桶中分出T升油(例如T=4)。
解:
令三个油桶的盛油情况为倒油过程的状态,则倒油过程就是状态变化的过程。为了记录倒油过程,程序引入倒油状态队列,
将倒油过程中产生的状态存储在队列中。队列的每个元素记录每次分油后各个油桶的分油后各个油桶的盛油量和倒油轨迹等有关信息。
程序反复从队列中取出第一个还未检查过的状态,对该状态下的每个油桶判断其是否可以倒出油,及是否可以倒进油。由于油桶没有刻度,
分油时只能将某个油桶倒满或倒空。程序分别按倒空或倒满两种可能的倒油动作执行不同的处理,产生新的倒油状态,
为避免某个倒油状态在队列中重复出现,程序只将未曾出现过的新状态及其倒油轨迹信息存入队列中,假定程序检查了相当多的状态后,
或能找到解,或能确定问题无解。
倒油程序算法如下:
算法---无刻度油桶分油
{
输入各桶容量和目标容量;
将初始状态存入倒油状态队列;
设置其它初始值;
do
{
对状态队列中第一个还未检查的元素
在还未检查完每个倒出的桶且还未找到解且还未确定无解情况下循环
if(倒出桶有油)
在还未检查完每个桶且还未找到解且还未确定无解情况下循环
if(当前桶不是倒出桶且桶还有空)
{
确定本次倒油量;
在队列中检查倒油后的结果状态是否在队列中出现;
if(结果状态不在队列中出现)
{
将结果状态和轨迹信息存入队列;
if(有桶中的油达到目标容量)
设置找到解标志;
}
}
if(还未找到解)
{
修正队列第一个还未检查过的元素指针;
if(队列中的元素都已检查过)
设置无解标志;
}
}while(还未找到解且还未确定无解);
if(找到解)
{
根据倒油步聚的轨迹信息,形成倒油步聚序列;
输出倒油步聚序列;
}
}
倒油队列中的元素应包含下列信息:各桶的盛油量,该状态是从哪一个桶(源桶)倒向哪一个桶(目标桶)而形成的,
形成该状态的元素在队列中的位置。根据以上算法编写如下程序。
程序代码如下:
#include#define N 100
#define BUCKETS 3
struct ele{
int state[BUCKETS]; /*各桶盛油量*/
int sbucket; /*源桶*/
int obucket; /*目标桶*/
int last; /*轨迹元素在队列中的下标*/
}q[N]; /*队列*/
int full[BUCKETS];
int i,j,k,found,unable,wi,wj,v,targ;
int head,tail;
void main()
{
/*输入各桶容量和目标容量*/
printf("Enter volume of buckets. ");
for(i=0;ifull[1]>full[2],相应代码在此*/
printf("Enter volume of targ. ");
scanf("%d",&targ); /*检查targ<=full[0]的代码在此*/
/*设置将初始状态存入倒油状态队列等初值*/
q[0].state[0]=full[0];
for(i=1;i0) /*倒出桶有油*/
/*在还未检查完每个油桶且还未找到解且还未确定无解情况下循环*/
for(j=0;jfull[j]-q[head].state[j])
v=full[j]-q[head].state[j];
else v=q[head].state[i];
wi=q[head].state[i]-v;
wj=q[head].state[j]+v;
/*在队列中检查倒油后的结果状态是否在队列中出现*/
for(k=0;k<=tail;k++)
if(q[k].state[i]==wi&&q[k].state[j]==wj) break;
if(k>tail) /*结果状态不在队列中出现*/
{
/*将结果状态和轨迹信息存入队列*/
tail++;
q[tail].state[i]=wi;
q[tail].state[j]=wj;
q[tail].state[3-i-j]=q[head].state[3-i-j];
q[tail].sbucket=i+1;
q[tail].obucket=j+1;
q[tail].last=head;
/*如有桶达到目标盛油量,则设置找到解标志*/
if(wi==targ||wj==targ)found=1;
}
}
if(!found) /*还未找到解*/
{
head++; /*修正队列第一个还未检查过元素指针*/
if(head>tail) /*队列中的元素都已检查过*/
unable=1; /*设置无解标志*/
}
}while(!found&&!unable); /*还未找到解且还未确定无解*/
if(found) /*找到解*/
{
/*根据倒油步聚的轨迹信息,形成倒油步聚序列*/
i=tail;
j=-1;
do /*原倒油步聚逆向链接,现改为正向链接*/
{
k=q[i].last;
q[i].last=j;
j=i;
i=k;
}while(j);
/*输出倒油步聚序列*/
for(k=q[k].last;k>=0;k=q[k].last)
{
printf("%5d to %2d:",q[k].sbucket,q[k].obucket);
for(i=0;ib->c->a
并且必须符合如下规则:
1.b(5斤桶)倒空后才能从a(8斤桶)中取油。
2.c(3斤桶)盛满后才能向a(8斤捅)中倒油。
我们设从a中往b倒油x次,从c往a倒油y次,那么最后a中剩下的油应该为8-
5x+3y斤,按照题意,我们得到如下方程,
8-5x+3y=4:
我们为了得到这个方程的解,应按照上述的倒油规则不断的倒下去,直到a中或b中
油的重量为4斤为止,另外也可以改变倒油的规则,看能否找到最好的倒油步聚。
代码:
#includeint i;
main()
{ int a,y,z;
printf("Input Full a ,Empty b,c,Get i:"); /*读入3个容器的容量和最后需要的数量*/
scanf("%d%d%d",&a,&y,&z,&i);
getti(a,y,z);
}
getti(int a,int y,int z)
{ int b=0,c=0; /*b,c为二个容器的实际重量*/
printf("a%d b%d c%d %4d%4d%4d ",a,y,z,a,b,c);
while(a!=i||b!=i) /*如果满足要求退出循环*/
{ if(!b) /*如果b为空,从a往b倒油*/
{ a-=y;b=y;
}
else if(c==z)
{ a+=z;c=0 /*如果c已满,从c往a倒油*/
}
else if(b>z-c)
{ b-=(z-c);c=z; /*如果b的重量大于c的剩余重量,倒满c*/
}
else
{ c+=b;b=0; /*否则将b中的油全部倒入c*/
}
printf("%4d%4d%4d ",a,b,c);
}
}
运行结果:
Input Full a, Empty b,c, Get i: 8 5 3 4
volume:a=8 b=5 c=3
start:8 0 0
3 5 0
3 2 3
6 2 0
6 0 2
1 5 2
1 4 3
4 4 0
展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
人人文库网所有资源均是用户自行上传分享,仅供网友学习交流,未经上传用户书面授权,请勿作他用。
关于本文
本文标题:分油问题C语言.doc
链接地址:https://www.renrendoc.com/p-57798621.html