主题:在一个瓶中装有80毫升化学溶剂,实验中需要精确地平分成两份,没有量具,只有两个杯子,其中一个杯子的容
在一个瓶中装有80毫升化学溶剂,实验中需要精确地平分成两份,没有量具,只有两个杯子,其中一个杯子的容量是50毫升,另一个是30毫升,试设计一个程序将化学溶剂对分成两个40毫升,并以最少步骤给出答案。
分析:三个杯子水的初始状态为:80、0、0,生成新结点状态的方法为:将一个不空的杯子水倒入一个不满的杯中,且结点状态不重复,直到生成目标结点为止。
算法步骤:
⒈数据库: 用数组d构成存放生成结点(杯子水状态)的队;数组p作为指向父结点的指针;t和s作为队头与队尾指针。
⒉结点的产生:
(1)将结点中不空的杯子水倒入一个不满的杯子中,生成新的结点并记下父结点位置;
(2)判断新结点是否已生成过, 以避免死循环;
(3)生成的结点若为目标结点,输出。
⒊搜索策略: 广度优先搜索。
源程序如下:
program ex3;
type
status= array [1..3] of integer;
const
v: array [1..3] of integer =(80,50,30);
var
d: array [1..200] of status;
p: array [1..200] of integer;
t,s,i,j: integer;
procedure draw(f: integer);{输出}
var
m: array [1..20] of integer;
i,j,k: integer;
begin
j:=0;
while f<>1 do begin
inc(j);
m[j]:=f;
f:=p[f];
end;
writeln;
writeln('Start: ',d[1,1]:3,d[1,2]:3,d[1,3]:3);
for i:=j downto 1 do begin
write('Step No.',j+1-i,': ');
for k:=1 to 3 do write(d[m[i],k]:3);
writeln;
end;
writeln('End.');
halt;
end;
function exampass(w: integer): boolean;{新结点是否以前生成过}
var
i: integer;
begin
for i:=1 to w-1 do
if (d[i,1]=d[w,1]) and (d[i,2]=d[w,2]) and (d[i,3]=d[w,3])
then begin
exampass:=false;
exit;
end;
exampass:=true;
end;
function isobject(w: integer): boolean;{是否为目标结点}
begin
if (d[w,1]=40) and (d[w,2]=40) then isobject:=true
else isobject:=false;
end;
begin {生成新结点,将一个不空的杯子水倒入一个不满的杯子中}
d[1,1]:=80; d[1,2]:=0; d[1,3]:=0;
p[1]:=0;
t:=1; s:=2;
repeat
for i:=1 to 3 do
if d[t,i]<>0 then
for j:=1 to 3 do
if (i<>j) and (d[t,j]<>v[j]) then begin
d[s]:=d[t];
d[s,j]:=d[s,j]+d[s,i];
d[s,i]:=0;
if d[s,j]>v[j] then begin
d[s,i]:=d[s,j]-v[j];
d[s,j]:=v[j];
end;
p[s]:=t;
if exampass(s) then begin
if isobject(s) then draw(s);
inc(s);
end;
end;
inc(t);
until t>=s;
writeln('NoWay');
end.
分析:三个杯子水的初始状态为:80、0、0,生成新结点状态的方法为:将一个不空的杯子水倒入一个不满的杯中,且结点状态不重复,直到生成目标结点为止。
算法步骤:
⒈数据库: 用数组d构成存放生成结点(杯子水状态)的队;数组p作为指向父结点的指针;t和s作为队头与队尾指针。
⒉结点的产生:
(1)将结点中不空的杯子水倒入一个不满的杯子中,生成新的结点并记下父结点位置;
(2)判断新结点是否已生成过, 以避免死循环;
(3)生成的结点若为目标结点,输出。
⒊搜索策略: 广度优先搜索。
源程序如下:
program ex3;
type
status= array [1..3] of integer;
const
v: array [1..3] of integer =(80,50,30);
var
d: array [1..200] of status;
p: array [1..200] of integer;
t,s,i,j: integer;
procedure draw(f: integer);{输出}
var
m: array [1..20] of integer;
i,j,k: integer;
begin
j:=0;
while f<>1 do begin
inc(j);
m[j]:=f;
f:=p[f];
end;
writeln;
writeln('Start: ',d[1,1]:3,d[1,2]:3,d[1,3]:3);
for i:=j downto 1 do begin
write('Step No.',j+1-i,': ');
for k:=1 to 3 do write(d[m[i],k]:3);
writeln;
end;
writeln('End.');
halt;
end;
function exampass(w: integer): boolean;{新结点是否以前生成过}
var
i: integer;
begin
for i:=1 to w-1 do
if (d[i,1]=d[w,1]) and (d[i,2]=d[w,2]) and (d[i,3]=d[w,3])
then begin
exampass:=false;
exit;
end;
exampass:=true;
end;
function isobject(w: integer): boolean;{是否为目标结点}
begin
if (d[w,1]=40) and (d[w,2]=40) then isobject:=true
else isobject:=false;
end;
begin {生成新结点,将一个不空的杯子水倒入一个不满的杯子中}
d[1,1]:=80; d[1,2]:=0; d[1,3]:=0;
p[1]:=0;
t:=1; s:=2;
repeat
for i:=1 to 3 do
if d[t,i]<>0 then
for j:=1 to 3 do
if (i<>j) and (d[t,j]<>v[j]) then begin
d[s]:=d[t];
d[s,j]:=d[s,j]+d[s,i];
d[s,i]:=0;
if d[s,j]>v[j] then begin
d[s,i]:=d[s,j]-v[j];
d[s,j]:=v[j];
end;
p[s]:=t;
if exampass(s) then begin
if isobject(s) then draw(s);
inc(s);
end;
end;
inc(t);
until t>=s;
writeln('NoWay');
end.