商人过河问题的Java编程解决
商人过河问题(二)java实现
商⼈过河问题(⼆)java实现反正我是没跑通。
⾃⼰调了很久。
不多说,直接贴代码。
运⾏不通过找我。
通⽤版实现。
package mechants_River;/*** m 商⼈⼈数* s 随从⼈数* dual 对象表⽰商⼈和随从的组成状态,也就是⼀次渡河⽅案。
* add minus 状态变迁的计算* @author tina**/public class Dual {int m, s;public Dual(int m, int s) {this.m = m;this.s = s;}Dual add(Dual e) {return new Dual(this.m + e.m, this.s + e.s);}Dual minus(Dual e) {return new Dual(this.m - e.m, this.s - e.s);}public boolean greaterOrEqual(Dual d){//System.out.println("is Valid"+this.m+" "+this.s+"----"+d.m+" "+d.s);return (this.m>=d.m&&this.s>=d.s? true:false);}}View Codepackage mechants_River;import java.util.ArrayList;import java.util.List;import java.util.Set;import java.util.TreeSet;public class Path {Dual carryingSchema[]; // ⼩船可提供的载⼈⽅案Dual initStatus; // 初始状态Dual endStatus; // 终⽌状态List<Node> path = new ArrayList<Node>(); // 过河路径Set<Node> iNode = new TreeSet(); // 孤⽴结点public Path(int merchant, int servant, int carrying) {initStatus = new Dual(merchant, servant);endStatus = new Dual(0, 0);buildCarryingSchema(carrying);findPath();if (path.isEmpty()) {System.out.println("Can't solve the problem");} else {for (Node e : path) {System.out.println(e);}}}public static void main(String[] args) {Path p = new Path(5, 5, 2);}public boolean isRepeat() {return path.contains(this);}/*** 构建渡河⽅案根据⼩船的最⼤可载⼈数且⼩船不能空计算可⾏⽅案每个⽅案表⽰⼀个dual 对象并把保存在carryingSchema中。
商人过河模型
商人过河模型商人过河摘要本文针对商人安全渡河的问题,采用多步决策的过程建立数学模型,求解得到了在随从没有杀人越货的情况下的渡河方案。
对于本题而言,在3名商人、3名随从、船的最大容量为2的情况下,首先定义了渡河前此岸的状态,并设安全渡河条件下的状态集定义为允许状态集合,接着得到渡河方案的允许决策集合,然后得到状态随渡河方案变化的规律,最后利用平面坐标分析法,并利用计算机进行了仿真,得到了一种商人安全渡河的方案。
但是,本文不仅仅是为了拼凑出一个可行方案,而是希望能找到求解这类问题的规律性,并建立数学模型,用以解决更为广泛的问题。
基于此目的,利用图解法和算法,得到最短路径的最优解。
但同时由于该算法遍历计算的节点很多,所以效率低,而且当有多个最短距离时,不能够将所有符合条件的情况逐一列出。
最后,从这类问题解得趣味性、合理性进行了深入讨论,得到了“传教士与野蛮人渡河”,“印度夫妻渡河”等问题通用的模型,并将其进行了推广。
这也是本文的一大特色。
关键词渡河问题状态集合决策集合平面坐标图解法算法一、问题提出问题: 三名商人各带一个随从过河,一只小船只能容纳两个人,随从们约定,只要在河的任何一岸,一旦随从人数多于商人人数就杀人越货,但是商人们知道了他们的约定,并且如何过河的大权掌握在商人们手中,商人们该采取怎样的策略才能安全过河呢?二、问题分析这个问题已经理想化了,所以我们无需对模型进行假设,该问题可以看作一个多步决策问题。
每一步,船由此岸划到彼岸或者由彼岸划回此岸,都要对船上的人员进行决策(此次渡河船上可以有几名商人和几名随从),在保证安全(两岸的随从都不比商人多)的前提下,在有限次的决策中使得所有人都到对岸去。
因此,我们要做的就是要确定每一步的决策,达到渡河的目标。
三、模型假设与建立记第次过河前此岸的商人数为k x , 随从数为k y ,1,2,,k m =,,0,1,2,3k k x y =定义状态:将二维向量(,)k k k S x y =定义为状态,将安全渡河状态下的状态集合定义为允许状态集合, 记为{},y |0,3; y 0, 1, 2, 31;y 0, 12;y 0, 1,2S x x x x =======()或或记第 次渡河船上的商人数为 k u ,随从数为k v .定义决策:将二维向量(,)k k k d u v = 定义为决策;允许决策集合 记作:{}(,)|+1,2D u v u v ==因为小船容量为2,所以船上人员不能超过2,而且至少要有一个人划船,由此得到上式。
C语言培训第26章商人过河游戏
26.2 问题分析及实现
➢ 26.2.1 问题分析 ➢ 26.2.2 问题实现 ➢ 26.2.3 程序运行
26.2 问题分析及实现
➢ 对于此问题,首先想到的前面提到的要 领:看清、想明、把握每一个细节。由 问题描述可知,我们要实现的是打印安 全过河的方案,即不触发杀人越货并能 安全过河的方案。
26.2.1 问题分析
➢ 我们的将要开发的程序,就是从所有过河方 案中,排除错误的方案,留下正确可行的方 案。
26.2.2 问题实现
➢ 本小节就来通过编程来实现商人过河的游戏。 ➢ 1. 采用结构体保存过程数据 ➢ 通过定义一个结构体类型,模拟商人过河时,
所有可能的方案及此方案的状态,即需要记 录当前河东(原点)有几位商人、几位仆人, 当前河西(目的地)有几位商人、几位仆人。 实现代码见随书光盘中的代码26-1.txt。
26.2.2 问题实现
➢ 2. 求解问题的主要实现函数 ➢ 由于渡河过程有两种情况:向东渡河,向西
返回,因此,与仆人个数是否合法。代 码如下(代码26-1.txt)。
26.2.2 问题实现
➢ 3. 求解问题的判断函数 ➢ 如果合法则继续递归查找剩下的商人和仆人
商人过河游戏
➢ C语言的功能是强大而又灵活的。特别是在 算法与数据结构上,其灵活性、高效性更加 明显。本章研究对商人过河问题的求解。
26.1 问题描述
➢ 三名商人各带一个随从乘船渡河,一只小 船只能容纳二人,由他们自己划行。随从 们密约,在河的任一岸,一旦随从的人数 比商人多,就杀人越货。但是如何乘船渡 河的大权掌握在商人们手中。商人们怎样 才能安全渡河呢?
过河的方案,否则为不合法的方案,则应该 将此方案放弃。放弃后,程序返回上一级, 继续递归判断其他情况是否合法,直到全部 情况递归完毕。代码如下(代码26-2.txt)
商人过河模型问题的求解
《数学建模实验》课程考试试题----商人安全过河数学建模与求解一.问题提出:4名商人带4名随从乘一条小船过河,小船每次自能承载至多两人。
随从们密约, 在河的任一岸, 一旦随从的人数比商人多, 就杀人越货.乘船渡河的方案由商人决定,商人们如何才能安全渡河呢二.模型假设:商人和随从都会划船,天气很好,无大风大浪,且船的质量很好,可以保证很多次安全的运载商人和随从。
三.问题分析:商随过河问题可以视为一个多步决策过程,通过多次优化,最后获取一个全局最优的决策方案。
对于每一步,即船由此岸驶向彼岸或由彼岸驶向此岸,都要对船上的人员作出决策,在保证两岸的商人数不少于随从数的前提下,在有限步内使全部人员过河。
用状态变量表示某一岸的人员状况,决策变量表示船上的人员状况,可以找出状态随决策变化的规律,问题转化为在状态的允许变化范围内(即安全渡河条件),确定每一步的决策,达到安全渡河的目标。
四.模型构成:k x ~第k 次渡河前此岸的商人数,k y ~第k 次渡河前此岸的随从数 k x , k y =0,1,2,3,4; k =1,2,… …k S =(k x , k y )~过程的状态,S ~ 允许状态集合,S={(x , y )| x =0, y =0,1,2,3,4; x =4 ,y =0,1,2,3,4; x =y =1,2,3} k u ~第k 次渡船上的商人数k v ~第k 次渡船上的随从数k d =(k u , k v )~决策,D={(u , v )| 21≤+≤v u ,k u , k v =0,1,2} ~允许决策集合 k =1,2,… …因为k 为奇数时船从此岸驶向彼岸,k 为偶数时船从彼岸驶向此岸,所以状态k S 随决策k d 的变化规律是1+k S =k S +k )1(-k d ~状态转移律求k d ∈D(k =1,2, …n), 使k S ∈S, 并按转移律由1S =(4,4)到达状态1+n S =(0,0)。
商人们怎样安全过河
看谁答得快
1、某甲早8时从山下旅店出发沿一路径上山,下午5时到达山顶 并留宿。次日早8时沿同一路径下山,下午5时回到旅店。某 乙说,甲必在两天中的同一时刻经过路径中的同一地点,为 什么? 2、某人家住T市在他乡工作,每天下班后乘火车于6时抵达T市 车站,他的妻子驾车准时到车站接他回家。一日他提前下班 搭早一班火车于5时半抵T市车站,随即步行回家,他的妻子 像往常一样驾车前来,在路上遇到他接回家时,发现比往常 提前了10分钟,问他步行了多长时间? 3、两兄妹分别在离家2千米和1千米且方向相反的两所学校上学, 每天同时放学后分别以4千米/小时和2千米/小时的速度步行回 家,一小狗以6千米/小时的速度从哥哥处奔向妹妹,又从妹妹 处奔向哥哥,如此往返直至回家中,问小狗奔波了多少路程?
图 状态s=(x,y) ~ 16个格点 解 法 允许状态S ~ 10个 点 允许决策D ~ 移动1或2格; k奇,左下移; k偶,右上移.
s1
d1
d1, d11给出安全渡河方案
d11
评注和思考
sn+1
ቤተ መጻሕፍቲ ባይዱ
1
2
3
x
规格化方法, 易于推广 考虑4名商人各带一随从的情况
习题
• 模仿这一案例,作下面一题: 人带着猫、鸡、米过河,船除需要 人划之外,至多能载猫、鸡、米三者之 一,而当人不在场时猫要吃鸡、鸡要吃 米。试设计一安全过河方案,并使渡河 次数尽量地少。
建模示例
问题(智力游戏)
商人们怎样安全过河
河
小船(至多2人)
随从们密约, 在河的任一岸, 一旦随从的人数比商人多, 就杀人越货.
但是乘船渡河的方案由商人决定. 3名商人 3名随从 商人们怎样才能安全过河?
商人们怎样安全过河-(附MATLAB程序完整)培训讲学
商人们怎样安全过河建立模型xk~第k次渡河前此岸的商人数yk~第k次渡河前此岸的随从数sk=(xk , yk)~过程的状态S={(x , y) x=0, y=0,1,2,3; x=3, y=0,1,2,3; x=y=1,2} uk~第k次渡船上的商人数vk~第k次渡船上的随从数dk=(uk , vk)~ 决策多步决策问题求dk到达sn+仁(0,0).模型求解穷举法~ 编程上机S={(x , y) x=0, y=0,1,2,3;x=3, y=0,1,2,3; x=y=1,2}图解法状态s=(x,y) ~ 16个格点允许状态~ 10个“专点允许决策~移动1或2格;k奇,左下移;k偶右上移.d1,•……,d11给出安全渡河方案xk, yk=0,1,2,3;k=1,2,|....S~允许状态集合uk, vk=0,1,2;k=1,2,..…u+v=1,2} ~允许决策集合~状态转移律n),使sk S,并按转移律由s仁(3,3)要求~在安全的前提下(两岸的随从数不比商人多),经有限步使全体人员过河D={(u , v)D(k=1,2,评注和思考规格化方法 ,易于推广考虑 4 名商人各带一随从的情况 程序%%%%%%%%%%%%%%%% 开始 %%%%%%%%%%%%%%%%%%%%%% function jueche=guohe clear all clc%%%%%%%%%% 程序开始需要知道商人和仆人数; %%%%%%%%%%%%% shangren=input(' 输入商人数目 : '); puren=input(' 输入仆人数目 : ');rongliang=input(' 输入船的最大容量 : ');if puren>shangren shangren=input(' 输入商人数目 :'); puren=input(' 输入仆人数目 :'); rongliang=input(' 输入船的最大容量 :');end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 决 策 生成jc=1; %决策向量放在矩阵 fori=0:rongliangfor j=0:rongliangif (i+j<=rongliang)&(i+j>0)d(jc,1:3)=[i,j ,1];d(jc+1,1:3)=[-i,-j,-1];jc=jc+2;endendj=0; end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 状态数 组生成kx=1; % 状态向量放在 A 矩阵中,生成方法同矩阵生成;for i=shangren:-1:0for j=puren:-1:0if ((i>=j)&((shangren-i)>=(puren-j)))|((i==0)|(i==shangren))% (i>=j)&((shangren-i)>=(puren-j)))|((i==0)|(i==shangren)) 为可以存在的状态的约束条件A(kx,1:3)=[i,j,1];%生成状态数组集合 D 'A(kx+1,1:3)=[i,j,0];kx=kx+2;endend 中, jc 为插入新元素的行标初始为 1; % 满足条 D={(u,v)|1<=u+v<=rongliang,u,v=0,1,2} %生成一个决策向量立刻扩充为三维; % 同时生成他的负向量; 由于生成两个决策向量,则 jc。
商人过河(C语言代码)
编程完成商人过河游戏:有三个商人带着三个随从和货物过河,船每次最多只能载两个人,由他们自己划行,并且如何乘船渡河的大权由商人掌握。
要求保证在过河期间的任一岸上商人的人数要大于或等于随从的人数,否则随从会杀死商人抢走货物。
设计一个符合上述要求的商人过河的游戏#include<stdio.h>#include<stdlib.h>void print() //游戏屏幕{system("cls");printf("****************************************************************\n");printf("* *\n");printf("* ^_^welcome to the game!^_^ *\n");printf("* *\n");printf("* Game rules: *\n");printf("* 3 men and 3 rateiners and goods to pass the river,the boat*\n");printf("* carrys 2 persons each time.In passing the river,at any bank *\n");printf("* number of men must be more than the number the rateiners , *\n");printf("* or the rateiners will kill the men and take the goods. *\n");printf("* Game operations: 1.Input the number of men and rateiners *\n");printf("* in turn. *\n");printf("* 2.Input error keys,the game will restart. *\n");printf("****************************************************************\n");}void began() //游戏开始界面{char ch;printf("\n\n");printf(" Press any key to start the game.(Q key to quit)...");scanf("%c",&ch);if(ch=='Q'||ch=='q')exit(0);}void xianshi(char *a,char *b) // 显示过河的状态{int ax=0,ay=0,bx=0,by=0; //ax,ay,bx,by分别表示岸两边的商人和仆人数int i,j;for(i=0;i<6;i++){if(*(a+i)=='M')ax++;if(*(a+i)=='S')ay++;if(*(b+i)=='M')bx++;if(*(b+i)=='S')by++;}printf("This bank\n");for(i=1;i<=ax;i++)printf("man ");printf("\n");for(i=1;i<=ay;i++)printf("rateiner ");printf("\n\n");printf("That bank\n");for(i=1;i<=bx;i++)printf("man ");printf("\n");for(i=1;i<=by;i++)printf("rateiner ");printf("\n\n");if(ax==0&&ay==0&&bx==3&&by==3){printf("congrarulation! You have finished the game!\n"); // 游戏成功提示exit(0);}}void pan(int ax,int ay,int bx,int by) // 判断过河时,岸两边的商人是否安全,即商人数不少于仆人数{if(ax<ay||bx<by){printf("The men are killed Game Over!\n");exit(0);}}main(){int i,x=0,y=0; //x,y分别表示每次过河时坐船的商人数和仆人数int ax=3,ay=3,bx=0,by=0; // ax,ay,bx,by分别表示岸两边的商人和仆人数char a[6],b[6]; //定义两个数组分别存放岸两边的人数system("color 1E"); //定义背景和字体颜色print();began();print();for(i=0;i<3;i++) //M代表商人,S代表仆人a[i]='M';for(i=3;i<6;i++)a[i]='S';for(i=0;i<6;i++)b[i]='0'; //游戏开始前的状态,即三个商人和三个仆人在等待过河xianshi(a,b); //开始前的状态do //用do-while循环{printf("Please input the number of man to that bank:");scanf("%d",&x);while(x<0||x>2) //判定过河的人数{printf("The wrong number,please input again:");scanf("%d",&x);}print();63xianshi(a,b);printf("Please input the number of rateiner to that bank:");scanf("%d",&y); //判定过河的人数while(y<0||y>2||x+y>2){printf("The wrong number,please input again:");scanf("%d",&y);}ax=ax-x;ay=ay-y;pan(ax,ay,bx,by);bx=bx+x;by=by+y; //一次过河后岸两边商人和仆人的人数print();for(i=0;i<6;i++) //数组设置为空{a[i]='0';b[i]='0';}for(i=0;i<ax;i++)a[i]='M';for(i=3;i<3+ay;i++)a[i]='S';for(i=0;i<bx;i++)b[i]='M';for(i=3;i<3+by;i++)b[i]='S';xianshi(a,b);printf("Please input the number of the man back to this bank:");scanf("%d",&x);while(x<0||x>2){printf("The wrong number,please input again:");scanf("%d",&x);}print();xianshi(a,b);printf("Please input the number of rateiner back to this bank:");scanf("%d",&y);while(y<0||y>2||x+y>2){printf("The wrong number,please input again:");scanf("%d",&y);}bx=bx-x;by=by-y;pan(ax,ay,bx,by);ax=ax+x;ay=ay+y;for(i=0;i<6;i++){a[i]='0';b[i]='0';}for(i=0;i<ax;i++) a[i]='M';for(i=3;i<3+ay;i++) a[i]='S';for(i=0;i<bx;i++) b[i]='M';for(i=3;i<3+by;i++) b[i]='S';print();xianshi(a,b);}while(1);}。
商人过河问题.
A (aij )nn 为 G 的邻接距阵,其中
1 aij 0
viv j E(G) viv j E(G)
i, j 1, 2, , n
定理 1:设 A(G) 为图 G 的邻接距阵,则 G 中从顶点 vi 到顶点 v j ,长度为 k 的道路的条
数为 Ak 中的 i 行 j 列元素.
证: 对 k 用数学归纳法 k 1 时,显然结论成立; 假设 k 时,定理成立, 考虑 k 1的情形.
其中 A 表示从南岸到北岸渡河的图的邻接距阵, B AT 表示从北岸到南岸渡河的图的
邻接距阵。
由定理 1、我们应考虑最小的 k ,s t ( AB)k A 中 1 行 10 列的元素不为 0,此时 2k 1
即为最少的渡河次数,而矩阵 ( AB)k A 中 1 行 10 列的元素为最佳的路径数目。
商人过河问题
三名商人各带一个随从乘船渡河,现有一只小船只能容纳两个人,由他们自己划行,若 在河的任一岸的随从人数多于商人,他们就可能抢劫财物。但如何乘船渡河由商人决定,试 给出一个商人安全渡河的方案。
首先介绍图论中的一个定理
G 是一个图,V(G)为 G 的顶点集,E(G)为 G 的边集。 设 G 中有 n 个顶点 v1, v2 , , vn ;
条,所以长为 k 1的从 vi 经 k 步到 vl 再一步到 v j 的道路共有 ai(lk) alj 条,故从 vi 经 k 1
n
步到 v j 的路径共有 ai(jk1)
a(k) il
alj
条.
l 1
下面分析及求解 假设渡河是从南岸到北岸,(m,n)表示南岸有 m 个商人,n 个随从,全部的允许状 态共有 10 个
v1 (3,3) v2 (3,2) v3 (3,1) v4 (3,(0,3) v8 (0,2) v9 (0,1) v10 (0,0)
商人过河问题
商人过河问题摘要:为了求解3个商人和3个随从的过河问题,用数学分析方法,建立数学模型,并且加以求解,展示动态规划思想的应用步骤。
最后利用计算机编程进行求解,获得过河问题的完整求解过程;有效地求解类似多步决策问题的作用。
关键词:多步决策计算机求解状态转移律图解法 MATLAB程序一.问题提出S个商人各带一个随从乘船过河,一只小船只能容纳K人,由他们自己划船。
商人们窃听到随从们密谋,在河的任意一岸上,只要随从的人数比商人多,就杀掉商人。
但是如何乘船渡河的决策权在商人手中,商人们如何安排渡河计划确保自身安全?二.问题的关键解决的关键集中在商人和随从的数量上,以及小船的容量上,该问题就是考虑过河步骤的安排和数量上。
各个步骤对应的状态及决策的表示法也是关键。
三.问题的分析在安全的前提下(两岸的随从数不比商人多),经有限步使全体人员过河。
由于船上人数限制,这需要多步决策过程,必须考虑每一步船上的人员。
动态规划法正是求解多步决策的有效方法。
它要求把解的问题一层一层地分解成一级一级、规模逐步缩小的子问题。
直到可以直接求出其解的子问题为止。
分解成所有子问题按层次关系构成一棵子问题树.树根是原问题。
原问题的解依赖于子问题树中所有子问题的解。
四.模型假设记第k次过河前A岸的商人数为XK,随从数为YK k=1,2,⋯ XK ,YK=0,1,2,3,将二维向量SK=(XK,YK)定义为状态.把满足安全渡河条件下的状态集合称作为允许状态集合。
记作S。
则 S={(XK ,YK)|(XK =0,YK =0,1,2,3),(XK =3,YK =0,1,2,3),(XK =YK =1)(XK =YK =2)}记第k次过河船上的商人数为UK,随从数为VK将二维向量DK=(UK ,VK)定义为决策。
由小船的容量可知允许决策集合(记作D)为D={(UK ,VK)|UK +VK=l,2}={(O,1);(O,2);(1,O);(1,1);(2,O)}五.模型建立:动态规划法正是求解多步决策的有效方法。
商人过河问题程序
end;
function jueche=guohe
%%%%%%%%%%%%%%%%%%%%%%
程序开始需要知道商人和仆人数;
n=input(‘输入商人数目:’,’12’);
nn=input(‘输入仆人数目:’,’12’);
nnn=input(‘输入船的最大容量:’,’20’);
if nn>n
return 0;
pointer=pointer-> next;
}
return 1;
}
}
int judge(int a,int b,int c,int d,int n) /*判断这个状态是否可行,其中使用了history函数*/
{
if(history(a,b,n)==0) return 0;
if(a> =0&&b> =0&&a <=3&&b <=3&&c> =0&&d> =0&&c <=3&&d <=3&&a+c==3&&b+d==3)
c=A(i,:)+d(j,:) ;
x=find((A(:,1)==c(1))&(A(:,2)==c(2))&(A(:,3)==c(3))) ;
v(i,x)=1; %x为空不会改变v值
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% dijstra算法
{
int x;
int y;
商人过河穷举法代码(java)
52524342525000 11
&& (tt[1]==0||tt[1]>=tt[0])&&(tt[0]>=0&&tt[1]>=0)){
//判断是否能采取此方案过河
int newVec[]=new int[14];
for(int k=0;k<=13;k++){
newVec[k]=vec[k];
//如果过河成功,输出过河的方案序列
}
if(times<12){
guohe(times+1,t,newVec);//过河次数小于12,继续递归
}
}
}
}
}
运行结果:
31524342513000 11
31524342525000 11
int begin[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0};
//初始化过河方案的序列,14位,最多可走14次,往返算2次
int num[] = {3,3};//初始化过河前此岸情况
guohe(1,num,begin);// 1是渡河次数,指现在进行第一次渡河
}
public static void guohe(int times,int[] num,int[] vec){
for(int i=0;i<=4;i++){//依次循环5种方案进行试着渡河
int t[]={0,0};
int tt[]={0,0};
t[0]=(int) (num[0mes));//此岸仆人数
t[1]=(int) (num[1]+d[i][1]*Math.pow(-1,times));//此岸商人数
商人随从过河
数学建模作业题目:商人随从过河队员:姓名:***姓名:***姓名:王*2011年08月25日商人过河问题摘要本文针对商人渡河的问题,建立分步决策模型,采用Dijkstra算法解决了商人和随从渡河问题。
根据题意用三维向量表示商人、随从和船的状态,并且定义此岸允许状态集合、彼岸允许状态集合及决策变量集合。
然后把此岸允许状态集合和彼岸允许状态集合中的每个元素视为节点,按照状态转移规律连接这些节点构成了一个连通图,寻找安全的渡河方案最终转化为从起始状态(节点)到最终状态(节点)的路径,用图论的Dijkstra算法找出所有路径,每一条路径对应一种渡河方案,整体方案如图1(实心点代表此岸,空心点代表彼岸,人数均为此岸人数),由图可知共有四种渡河方案。
图1 整体渡河方案关键词:分步决策 Dijkstra算法三维向量连通图1 问题重述三名商人各带一名随从过河,随从们密约, 在河的任一岸, 一旦随从的人数比商人多, 就杀人越货.但是乘船渡河的方案由商人决定.商人们怎样才能安全过河?(如果推广到四名商人四个随从又如何?)2 模型假设(1)商人和仆人都会划船,并且仆人听从商人的调度 (2)商人和仆人每次渡船都能安全到达(3)船的质量很好,在多次满载情况也能正常运作3 符号说明(1) k s 第k 次渡河前此岸商人和仆人的数量称为状态向量;(2) ks '第k 次渡河前彼岸商人和仆人的数量称为状态向量; (3) S 所有安全渡河条件下状态向量的集合; (4) S '所有安全渡河条件下状态向量的集合; (5) k d 第k 次渡河船上商人和仆人的数称为决策向量; (6) D 所有安全渡河条件下决策向量的集合; (7) k x 第k 次渡河前此岸的商人数;(8) kx ' 第k 次渡河前彼岸的商人数; (9) k y 第k 次渡河前此岸的仆人数;(10) ky ' 第k 次渡河前此岸的仆人数; (11) k u 第k 次渡船上的商人数; (12) k v 第k 次渡船上的仆人数。
过河问题的代码实现
过河问题的代码实现/*最佳方案构造:以下是构造N个人(N≥1)过桥最佳方案的方法:1) 如果N=1、2,所有人直接过桥。
2) 如果N=3,由最快的人往返一次把其他两人送过河。
3) 如果N≥4,设A、B为走得最快和次快的旅行者,过桥所需时间分别为a、b;而Z、Y为走得最慢和次慢的旅行者,过桥所需时间分别为z、y。
那么当2b>a+y时,使用模式一将Z和Y移动过桥;当2b<a+y时,使用模式二将Z和Y移动过桥;当2b=a+y时,使用模式一将Z和Y移动过桥。
这样就使问题转变为N-2个旅行者的情形,从而递归解决之。
……A Z →A ←……也就是“由A护送到对岸,A返回”,称作“模式一”。
…………第n-2步: A B →第n-1步: A ←第n步:Y Z →第n+1步: B ←……这个模式是“由A和B护送到对岸,A和B返回”,称作“模式二”。
*/#include <stdio.h>#include <stdlib.h>int cmp(const int *a, const int *b){return *a - *b;}int main(){int *array = NULL;int total, n, tmp;int fast1, fast2, slow1, slow2;scanf("%d", &n);total = 0;if(array){free(array);}array = (int *)malloc(sizeof(int) * n);tmp = n;while(tmp --){scanf("%d", &array[tmp]);}/*库函数提供的快速排序算法,只需要实现比较函数就可以了*/ qsort(array, n, sizeof(int), cmp);fast1 = array[0]; //最快的fast2 = array[1]; //次最快的slow1 = array[n - 2]; //次慢slow2 = array[n - 1]; //最慢的while (1){/*如果只有一个或两个或者三个,以最慢的人为参考*/if(1 == n){total += slow2;break;}if(2 == n){total += array[1];break;}if (3 == n){total += slow2 + slow1 + fast1;break;}/*根据情况分别用模式一和模式二护送最慢的两个过桥*/ if(2 * fast2 >= fast1 + slow1){/*用最快的护送最慢的两个所需要的时间*/total += (slow1 + slow2 + 2 * fast1);}else{/*用最快的两个护送最慢的两个所需要的时间*/total += 2 * fast2 + fast1 + slow2;}n -= 2;slow2 = array[n - 1];slow1 = array[n - 2];}if(array){free(array);}printf("%d\n", total); return 0;}。
商人过河问题(一)
使用图解法进行求解:
当n=2时,状态转移如下图所示,即(2,2)→(1,1) Or (2,0)→(2,1)→(0,1) → (1,1)→(0,0)
当 时无法安全渡河,如n=4时如下图,d7无法作不重复的转移。
同遇到了windumpcapturelength截断的问题经查文档发现加上s0参数可以实现捕获完整的frame
商人过河问题(一)
问题描述:
如果有n名商人,有n名随从,如何建模?设计求解算法?是否n为任意值均有解?
问题解答:
假设第k次渡河前, xk表示此岸的商人数, yk为随从数。S表示安全渡河Fra bibliotek件下的状态集合:
S={(X,Y)|X=0,Y=0,1,2,3...N:X=N,Y=0,1,2,3...N;X=Y=1,2,3...N-1} (1)
允许决策集合记为D
D={(U,V)|1≤U+V≤2,U,V=0,1,2}
(2)
表示渡河状态
Sk+1 =Sk+(-1)kdk(3)
求解上述(1)、(2)、(3),使得状态 从初始状态(n,n)到达状态(0,0)。
商人带工人过河matlab程序
商人带工人过河matlab程序function boat(m,k)%输入变量m表示商人或工人数,k表示小船的最大容量.%%本程序编程思路是用单元型变量B和C分别表示允许状态集合S和决策d.%将S中的每一个元素用所有决策d按照状态转移律迭代.%对于每一步中每一个元素的迭代结果,剔除掉不符合事实的情况.%当某一个迭代结果是[0,0]时,说明当商人或工人个数是m个,小船的最大容量是k时可以在有限的步骤下安全过河.%当所有迭代结果都被剔除时,说明当商人或工人个数是m个,小船的最大容量是k个时不可以在有限的步骤下安全过河.%%本程序的优点是可以计算出小船最大容量超过2时的情况.%%下面三个for语句是根据参数m算出所有允许状态集合S中的元素,用B表示.for i=1:m+1A=[m,i-1];B{i}=A;endfor i=m+2:2*mA=[i-(m+1),i-(m+1)];B{i}=A;endfor i=2*m+1:3*m+1A=[0,i-(2*m+1)];B{i}=A;end%下面的for语句是根据参数k算出所有决策d,用C表示. t=1;for u=0:1:kfor v=0:1:kif u+v>=1&u+v<=kC{t}=[u,v];t=t+1;endendendD{1,1}=[m,m];% D{1,1}表示初始状态.w=1;% w控制是否能够迭代成功.h=1;% h控制元素的个数.j=2;% j表示迭代的次数.x=0;% x是用来剔除掉不在允许状态集合中的元素.y=0;% y是防止重复剔除同一个元素.l=0;% l使用来标记元素是否被剔除.z(1)=0;z(2)=1;% z(j)表示上一步迭代后所剩下的所有元素.while w>0% p表示可以进行下一步迭代的所有元素.for p=z(j-1)+1:z(j)% q表示每一个元素要经过k*(k+3)/2种决策迭代.for q=1:k*(k+3)/2D{h+1,j}=D{p,j-1}+(-1)^(j-1).*C{q};h=h+1;l=1;%下面的for语句是核查迭代结果是否在允许状态集合B 中.for e=1:3*m+1if D{h,j}==B{e}x=1;break;endendif x==0h=h-1;y=1;l=0;end%下面的if语句是剔除掉本次迭代过程中出现的重复元素.if j>2&y==0for i=z(j)+1:h-1if D{h,j}==D{i,j};h=h-1;l=0;break;endendend%下面的if语句是剔除掉以前重复的元素.if j>2&y==0if j==3for i=z(1)+1:z(2)if D{h,j}==D{i,j-2} h=h-1;l=0;break;endendelsefor i=z(j-2)+1:z(j-1)if D{h,j}==D{i,j-2} h=h-1;l=0;break;endendendendif l==1for g=1:j-1D{h,g}=D{p,g};endendif l==1&D{h,j}==[0,0]w=-1;%w=-1表示商人和工人可以在有限的步骤下安全过河.break;endx=0;y=0;l=0;endif w==-1;%w=-1表示商人和工人可以在有限的步骤下安全过河.break;endendj=j+1;z(j)=h;if z(j)==z(j-1)w=-2;%w=-2表示商人和工人不可以在有限的步骤下安全过河.break;endendif w==-1disp('商人和工人可以在有限的步骤下安全过河') disp('步骤如下:')for g=1:j-1D{h,g}endendif w==-2disp('商人和工人不可以在有限的步骤下安全过河') end。
八人过河问题的Java编程实现
八人过河问题的Java编程实现
邹秀斌
【期刊名称】《电脑编程技巧与维护》
【年(卷),期】2016(000)021
【摘要】针对八人过河问题,设计了一种有效回溯算法,Java编程实现了八人过河的过河方案,同时,该算法亦可以得到农夫过河问题的过河方案,并给出有效的Java 程序来解决此类过河问题.
【总页数】6页(P14-19)
【作者】邹秀斌
【作者单位】江汉大学数计学院,武汉430056
【正文语种】中文
【相关文献】
1.Android平台Java和C++混合编程实现 [J], 周国瑞
2.Java编程实现WEKA数据文件的生成 [J], 胡海斌
3.商人过河问题的Java编程解决 [J], 王国全
4.浅析用Java编程实现RSA算法的过程 [J], 周君
5.利用java编程实现网络安全通信 [J], 孙杰
因版权原因,仅展示原文概要,查看原文内容请购买。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
商人过河问题的Java编程解决转自:“电脑编程技巧与维护”/摘要为商人过河问题建立数学模型,归结为路径搜索问题,并给出一个通用的Jav程序来解决此类问题。
关键词商人过河,二元组,链表,集合一、描述商人过河问题是一个传统的智力问题。
其描述如下:三名商人各带一名随从乘船渡河,—只小船只能容纳二人,由他们自己划行。
随从们密约,在河的任一岸,一旦随从的人数比商人多,就杀人越货。
但是如何乘船渡河的大权掌握在商人们手中,商人们怎样才能安全渡河呢?商人过河问题可以看作一个多步决策过程,通过一系列决策步骤逼近决策目标,并最终达到决策目标。
对于该问题的每一步决策,就是要对船由此岸驶向彼岸或由彼岸驶回此岸的人员(包括商人和随从)作出规划,在保证商人安全的前提下,通过有限的步骤,实现人员全部过河的目标。
二、分析针对这一具体问题,可以经过一番精心安排,找到一个解决方案。
不过,本文希望对这一问题进行发展和延伸,建立起数学模型,发现其中蕴含的规律,并借助计算机的运算能力,找到一个通用的一般解法。
在商人过河问题中,用一个二元组来表示岸上商人和随从的组成(m,s),其中m表示商人人数,s表示随从人数,每个组合可以视为一种状态。
所有可能的状态可以表示为集合:S0={(m, s)| 0≤m≤3; 0≤s≤3}安全状态要求商人人数为0,或者大于等于随从人数,因此,所有的安全状态可以表示为集合:S1={(m, s)| m=0, s=0,1,2,3; m=3, s=0,1,2,3; m=s=1,2}二元组(m,s)也可以表示一次渡河方案,其中m表示船载的商人人数,s表示船载的随从人数。
则所有的渡河方案可以表示为集合:S2={(m , s)|0≤m;0≤s;0≤m+s≤2 }一次渡河决策可以表示为:(m, s)K+1 = (m , s)K- (-1)K(u, v)KK = 0,1,2,3…(m , s)K 为第K次渡河时,岸上的商人和随从的组成,(u, v)K为第K次渡河方案,K从0开始。
整个决策方案就是要找到有限步渡河决策,使商人和随从的人数组成从原始状态(3,3),经由一系列中间的安全状态,迁移到最终状态(0,0)的过程。
三、编程建立前面的数学模型后,即找到一条从状态(3,3)到(0,0)的路径,可以编写程序,利用计算机的计算能力,通过穷举法找到一条状态迁移路径。
1.类二元组类Dual实现问题分析中提到的二元组,其主要代码如下:class Dual {int m, s;public Dual(int m, int s) {this.m = m; this.s = s;}// 加法Dual add(Dual e) {return new Dual(this.m + e.m, this.s + e.s );}// 减法Dual minus(Dual e) {return new Dual(this.m - e.m, this.s - e.s );}…}当使用类Dual的成员m表示商人人数,s表示随从人数时,则一个Dual对象就可以用来表示商人和随从的组成状态,也可以表示一次渡河方案。
类Dual 的方法add()和minus()实现了状态变迁的计算。
2.类结点类Node表示整个渡河方案中的每个步骤,每个结点由结点状态(商人和随从的人数组成) 、渡河方向和渡河方案组成。
其主要代码如下:class Node implements Comparable<Node>{Dual status; // 结点状态int direction; // 渡河方向int idx; // 索引,指向小船的载人方案carryingSchema[]public Node(Dual status, int direction, int idx) {this.status = status;this.direction = direction;this.idx = idx;}public static final int FORWARD = 0; // 渡河方向:前进public static final int BACKWARD = 1; // 渡河方向:返回…}在前面分析中,渡河问题其实归结为一个路径查找问题,因此,需要在类Node 中实现一系列与路径查找问题有关的方法。
3.状态迁移计算当前状态,执行指定的渡河方案后,所迁入的状态。
当渡河方向为FORWARD时,调用Dual对象的minus()方法;当渡河方向为BACKWARD时,调用Dual对象的minus()方法。
数组carryingSchema为渡河方案,idx为指向数组carryingSchema的索引。
Dual nextStatus() {return direction == FORWARD ?this.status.minus(carryingSchema[idx]) :this.status.add(carryingSchema[idx]);}4.结点是否相等类Node需要实现equals(),以覆盖继承Java基类Object的equals()方法,实现对结点是否相等进行比较。
public boolean equals(Object e) {if( this == e ) return true;if( !(e instanceof Node) ) return false;Node o = (Node)e;return this.status.equals(o.status) &&this.direction == o.direction &&this.idx == o.idx ;}5.结点是否有效判断结点是否有效,根据实际问题,当向前渡河时,要求本岸商人和随从人数分别大于等于渡河方案指定的商人和随从人数;当小船返回时,要求对岸商人和随从人数分别大于等于渡河方案指定的商人和随从人数public boolean isValid() {return this.direction == FORWARD ?status.greaterOrEqual(carryingSchema[idx]):initStatus.minus(status).greaterOrEqual(carryingSchema[idx]);}6.状态是否安全判断结点的状态是否有效,这是实际问题的一具体约束,即要求结点状态中商人人数或者为0,或者不小于随从人数。
public boolean isSecure() {Dual next = this.nextStatus();return (next.m==0 || next.m >= next.s) &&(initStatus.m-next.m==0 || initStatus.m-next.m >=initStatus.s-next.s );}7.结点是否重复判断结点是否已经包含在路径中。
在路径查找问题中,需要避免出现环路,因此,需要消除结点重复。
在下面的方法中,变量path指定路径,contains()方法暗含对Node的equals()方法的调用,来判断两个结点是否相等。
public boolean isRepeat() {return path.contains(this);}8.是否达到终点判断结点的下一状态是否达到目标状态,如果是,则结束路径搜索。
public boolean isEnd() {return this.nextStatus().equals(endStatus);}9.是否达到孤立结点孤立结点是指当路径进入该点后,无法继续前进,此时路径必须向后回退,同时标记该点为孤立结点。
在路径搜索时,要避开已知的孤立结点。
public boolean isIsolated() {int direction = this.nextDirection();Dual status = this.nextStatus();for(Node e: iNode) {if(direction == e.direction && status.equals(e.status)){return true;}}return false;}10.实现Comparable接口类Node实现Compareble接口,需要给出Compareble接口中的抽象方法compareTo()的具体实现。
在程序中,使用集合(TreeSet)来保存孤立结点,Java 集合(Set)调用方法compareTo()来判断元素是否重复,集合具有自动过滤重复元素的功能。
需要指出的是,判断孤立结点时,需要考虑当前状态以及渡河方向。
public int compareTo(Node e) {return this.toString2().compareTo(e.toString2());}private String toString2() {return this.status+ (direction == FORWARD ? " ---> " : " <--- ");}11.类路径类Path使用穷举法,搜索一条路径,解决商人过河问题。
为了通用地解决该类问题,类Path的构造方法允许指定商人人数、随从人数和小船的可载人数。
路径结点的初始状态由给定的商人人数和随从人数构成的二元组;终止状态为渡河完成,即二元组(0,0)。
类Path使用数组carryingSchema来表示小船可提供的载人方案。
使用数组链表(ArrayList)对象path来保存渡河路径,ArrayList为有序的数据结构,而渡河路径也要求有序性。
使用集合(TreeSet)来储存在搜索过程中遇到的孤立结点,集合不允许重复元素,符合储存孤立结点的数据结构的要求。
类Path的构造方法,调用方法buildCarryingSchema(),构造小船的可行渡河方案后;再调用方法findPath()来搜索过河路径;最后,如果path不空,即存在过河路径,则输出结果。
class Path {Dual carryingSchema[]; //小船可提供的载人方案Dual initStatus; //初始状态Dual endStatus; //终止状态List<Node> path = new ArrayList<Node>(); //过河路径Set<Node> iNode = new TreeSet(); //孤立结点public Path(int merchant, int servant, int carrying ) {initStatus = new Dual(merchant, servant); //初始状态endStatus = new Dual(0, 0); //终止状态// 构建小船可提供的载人方案buildCarryingSchema(carrying);// 搜索过河路径findPath();if(path.isEmpty()) { //过河路径不存在System.out.println ("Cannot solve the provlem.");}else { //输出过河路径for(Node e: path) System.out.println(e);}}…}12.构建渡河方案方法buildCarryingSchema(),根据小船的最大可载人数且小船不能空计算出小船的所有可行的载人方案,每个方案表示为一个Dual对象,这些方案保存在数组carryingSchema中。