“过河”问题的解法
陕西省西安市长安区第二中学杨西武
【关键词】
迪克斯特拉算法,图论,最短路径
【内容提要】
信息学奥林匹克竞赛,各类资料中都涉及“过河”一题,但都没有给出详解及程序。
历届考题也没有涉及到,原因是其测试数据不便给出多组。
但此题对考察学生的分析能力和解题能力却很有帮助。
本文旨在给出其详解。
【问题描述】
某人m带一只羊s,一只狼w和一筐白菜v过河。
没有船,他每次游过河时只能带一件东西,当没有人管理时,狼和羊不能相处,羊和白菜不能相处。
在这些条件的约束下,他怎样才能将三件东西从左岸带往右岸?试编程给出一组过河次数最少的方案。
【问题分析】
用无向图描述上述问题的解法路径
用结点代表状态
例如:初始状态v1可记为
{}>
Φ
<,
,
,
,v
w
s
m(即,人、羊、狼、
白菜皆在左岸,右岸为空,这是一种安全状态,即满足约束条件
的状态)。
最终状态v10可记为
{}>
Φ
<v
w
s
m,
,
,
,;
当人和羊过河后的状态可记为
{}{}>
<s
m
v
w,
,
,(即,狼和白菜
在左岸,人和羊在右岸,这也是一种完全状态)。
可根据约束条件写出所有的安全状态:
即:①{}>
Φ
<,
,
,
,v
w
s
m
②{}{}>
<s
m
v
w,
,
,
③
{}{}> <s
v
w
m,
,
,
④
{}{}> <w
v
s
m,
,
,
⑤
{}{}> <v
w
s
m,
,
,
⑥
{}{}> <v
w
s
m,
,
,
⑦
{}{}> <v
w
m
s,
,
,
⑧
{}{}> <v
s
m
w,
,
,
⑨{}{}><w s m v ,,,
⑩{}>Φ<v w s m ,,,,
将这些安全状态分别用结点v1v2……v10表示
若结点vi 经过一次过河可以到达结点vj ,则可以认为vi 和vj 之间有一条边,于是可以得到如下无向图:
从v1到v10的一条路径,即表示该题的一种解法
求过河次数最少的的方案也就是该图的一条最短路径
【算法】
①模拟题意,找出所有安全状态(见过程starter )
②模拟题意,找出各结点之间的关联,即建立图(见过程create )
③用迪克斯特拉算法,求出最短路径并打印。
【源代码】
program MWSV;
type
way=record
num:integer;
dist:integer;
next:0..16;
end;
boat=record
m,w,s,v:0..1;
end;
var b:array[1..16]of boat; n:integer;
V 4
9
r:array[1..16,1..16]of 0..1;
procedure starter; {根据约束条件,求出所有安全状态}
var bb:boat;mm,ww,ss,vv:0..1;
begin
n:=0;
for mm:=0 to 1 do
for ww:=0 to 1 do
for ss:=0 to 1 do
for vv:=0 to 1 do
if not((ss<>mm)and((ss=ww)or(ss=vv)))then
begin
inc(n);
b[n].m:=mm;
b[n].s:=ss;
b[n].w:=ww;
b[n].v:=vv;
end;
end;
procedure create; {根据渡河条件,建立各结点间的联系}
var i,j:integer;
function ifln(b1,b2:boat):boolean;
var a,b:0..4;bz:boat;
begin
if b1.m<>1 then begin
bz:=b1;
b1:=b2;
b2:=bz;
end;
a:=b1.m+b1.w+b1.s+b1.v;
b:=b2.m+b2.w+b2.s+b2.v;
ifln:=false;
if (b1.m+b2.m=1)and(a<>b)and(abs(a-b)<3)then
if
not((b1.w=0)and(b2.w=1)or(b1.s=0)and(b2.s=1)or(b1.v=0)and(b2.v=1) )
then ifln:=true;
end;
begin
for i:=1 to n do
for j:=1 to n do r[i,j]:=0;
for i:=1 to n do
for j:=i+1 to n do
if ifln(b[i],b[j]) then begin
r[i,j]:=1;
r[j,i]:=1;
end;
end;
procedure dijstra; {求出一条最短路径并打印}
var s:array[1..16] of way;
tr:array[1..16]of 0..1;
h,t,i,tt,j,dis:integer;
writ:way;
procedure print(bx:boat);
var s1,s2:string[4];
begin
s1:='';s2:='';
if (bx.m=0)then s1:=s1+'m' else s2:=s2+'m';
if (bx.w=0)then s1:=s1+'w' else s2:=s2+'w';
if (bx.s=0)then s1:=s1+'s' else s2:=s2+'s';
if (bx.v=0)then s1:=s1+'v' else s2:=s2+'v';
writeln(s1:4,'**',s2:4);
end;
procedure insert(nn:integer);
begin
inc(t);
s[t].num:=nn;
tr[nn]:=1;
s[t].dist:=1;
end;
begin
for i:=1 to n do tr[i]:=0;
t:=0;
tt:=0;
h:=1;
insert(n);
s[1].next:=0;
while t>tt do
begin
tt:=t;
for j:=h to t do
for i:=1 to n do
if (tr[i]=0)and(r[i,s[j].num]=1)then insert(i); for i:=tt+1 to t do
begin
dis:=10000;
for j:=h to tt do
if (s[j].dist<dis)and(r[s[i].num,s[j].num]=1)then
begin
s[i].next:=s[j].num;
dis:=s[j].dist;
end;
s[i].dist:=s[i].dist+dis;
end;
end;
for i:=1 to n do if s[i].num=1 then j:=i;
i:=1;
while s[j].next<>0 do
begin
print(b[i]);
i:=s[j].next;
for h:=1 to n do if s[h].num=i then j:=h;
end;
print(b[n]);
writeln;
end;
BEGIN
starter;
create;
dijstra;
END.
【参考文献】
①《信息学奥林匹克高级本》南京大学出版社出版
②《全国信息学奥林匹克联赛培训教程》吴文虎著
③《数据结构与算法设计——pascal语言》北京理工大学出
版社出版。