数学建模

您所在的位置:网站首页 在河中央的是一条小船英文 数学建模

数学建模

2023-10-19 02:51| 来源: 网络整理| 查看: 265

商人过河问题 1.问题重述

三名商人各带一个随从乘船渡河,一只小船只能容纳二人,由他们自己划行。随从们密约,在河的任一岸,一旦随从的人数比商人多,就杀人越货。但是如何乘船渡河的大权掌握在商人们手中,商人们怎样才能安全渡河呢?

2.问题分析

该问题是一个多步决策的问题,商人的下一步决定方案依赖于此时的状态,同时商人可以选择的方案有多种可能,因此,要想顺利将商人送达到对岸,需要对每一步进行决策和假设,通过一步步推理,分析出最后的结果

3.模型假设 将商人和随从的数目抽象成具体数值将河的此岸和彼岸抽象成两种不同的状态,比如说是0和1 4.符号说明 基于递归的方法

假设商人的人数是m,随从的人数是n,船的容量是k。

5.模型的建立和求解 基于递归的方法

记第k次渡河前彼岸(和数学模型(第四版)姜启源 谢金星 叶俊的不一样)的商人数为x,随从数为y, k = 1 , 2 , … k=1,2,\dots k=1,2,…, x = 0 , 1 , 2 , … , m x=0,1,2,\dots,m x=0,1,2,…,m, y = 0 , 1 , 2 , … , n y=0,1,2,\dots,n y=0,1,2,…,n,将二维向量 s = ( x , y ) s=(x,y) s=(x,y)定义为人员状态,安全渡河条件下的状态集合称为允许人员状态集合,记作 S S S S = { ( x , y ) ∣ x > y ∧ m − x > n − y } S=\{(x,y)|x>y \land m-x>n-y\} S={(x,y)∣x>y∧m−x>n−y} 首先需要注意到,此岸的决策恰好与彼岸决策相反,因此,针对此岸和彼岸的状态,需要不同的决策策略。不妨令船在此岸的状态抽象成0,船在彼岸的状态抽象成1。记三元组x, y, d表示彼岸的商人人数、随从人数以及此事船所在的河岸。于是,该事件的起始状态是(0, 0, 0),即彼岸没有商人和随从,所有人都在此岸,且船在此岸;事件的结束状态是(m, n, 1),即次岸没有商人和随从,所有人都在彼岸,且船在彼岸。

假设第k次的状态是(x, y, d),那么他的下一次的状态只能是在 ( S , d ′ ) (S, d') (S,d′)中,所以需要遍历所有可以到达的状态点即可。

6.附录 基于递归的方法的C++代码 #include #include #include #include #include #include #include using namespace std; typedef struct node { int x, y, d; shared_ptr prev;// 记录父节点的信息 node(shared_ptr n = nullptr):prev(n) {} }node; const int N = 100, M = N * N, mask = 0x1; int feasible_state[N][N];// 所有可行的位置点 int state[2][N][N];// 所有可行的状态点 判定状态是否遍历过 (0, 0, 0) 和 (0, 0, 1)是不同的状态 pair action[2][N * N];// 所有可行的决策策略 int m, n, k;// 商人、随从的数量和船的容量 int total_action = 0, all_cnt = 0, ans_cnt = 0, min_lens = 0x3f3f3f3f;// 所有的决策的数目,所有可行方案的数量,最少决策方案的数量,最少方案的决策步数 vector answer_tmp; vector answer;// 所有解的存放 node head_state;// 起点 void init(); void run(shared_ptr now); bool same(shared_ptr now); void show_ans(); int main() { printf("请输入商人、随从、船容量的信息:\n"); scanf("%d%d%d", &m, &n, &k); init(); run(make_shared(head_state)); show_ans(); system("pause"); return 0; } /** * 初始化所有合法的行动 * 初始化所有合法的状态 * */ void init() { // action[0][]是去向的行动 // action[1][]是回向的行动 // 使用pair存二维的方向 int method_cnt = 0; for(int r = 1; r -j, j - r}; total_action = max(total_action, method_cnt); // 所有可达点都是1 for(int j = 0; j shared_ptr last = make_shared(now->prev), to(new node); for(int i = 0; i shared_ptr tmp(to); stack s; while(tmp != nullptr) { s.push(*tmp); tmp = tmp->prev; } answer_tmp.push_back(s); all_cnt++; continue; } if(feasible_state[to->x][to->y] == 1 && (last == nullptr || !same(to)))// 到达可行点且没有绕回去 { run(to); } } } /** * 判定是否出现重路 * */ bool same(shared_ptr now) { memset(state, 0, sizeof(state)); for(; now != nullptr; now = now->prev) if(state[now->d][now->x][now->y] == false) state[now->d][now->x][now->y] = true; else return true; return false; } /** * 展示所有点 * */ void show_ans() { ofstream answer_file; answer_file.open("./answer_file.txt", ios::out | ios::trunc); for(auto stk : answer_tmp) { vector vec; while(!stk.empty()) { vec.push_back(stk.top()); stk.pop(); } answer.push_back(vec); } for(auto vec : answer) min_lens = min(min_lens, (int)vec.size()); for(auto vec : answer) if(vec.size() == min_lens) ans_cnt++; if(answer_file.is_open()) { for(auto vec : answer) { if(vec.size() == min_lens) { for(node n : vec) answer_file if(vec.size() == min_lens) { for(node n : vec) printf("(%d,%d,%d)->", n.x, n.y, n.d); printf("\n"); } } } }

参考 商人过河问题



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3