“过河”问题的解法

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

“过河”问题的解法

陕西省西安市长安区第二中学杨西武

【关键词】

迪克斯特拉算法,图论,最短路径

【内容提要】

信息学奥林匹克竞赛,各类资料中都涉及“过河”一题,但都没有给出详解及程序。历届考题也没有涉及到,原因是其测试数据不便给出多组。但此题对考察学生的分析能力和解题能力却很有帮助。本文旨在给出其详解。

【问题描述】

某人m带一只羊s,一只狼w和一筐白菜v过河。没有船,他每次游过河时只能带一件东西,当没有人管理时,狼和羊不能相处,羊和白菜不能相处。在这些条件的约束下,他怎样才能将三件东西从左岸带往右岸?试编程给出一组过河次数最少的方案。【问题分析】

用无向图描述上述问题的解法路径

用结点代表状态

例如:初始状态v1可记为

{}>

Φ

<,

,

,

,v

w

s

m(即,人、羊、狼、

白菜皆在左岸,右岸为空,这是一种安全状态,即满足约束条件

的状态)。最终状态v10可记为

{}>

Φ

w

s

m,

,

,

,;

当人和羊过河后的状态可记为

{}{}>

m

v

w,

,

,(即,狼和白菜

在左岸,人和羊在右岸,这也是一种完全状态)。

可根据约束条件写出所有的安全状态:

即:①{}>

Φ

<,

,

,

,v

w

s

m

②{}{}>

m

v

w,

,

,

{}{}>

v

w

m,

,

,

{}{}>

v

s

m,

,

,

{}{}>

w

s

m,

,

,

{}{}>

w

s

m,

,

,

{}{}>

w

m

s,

,

,

{}{}>

s

m

w,

,

,

⑨{}{}>

⑩{}>Φ

将这些安全状态分别用结点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

相关文档
最新文档