c++写一段野人传教士过河问题的代码,要求 输入:牧师人数(即野人人数)n,小船一次至多载客人数c。 输出:若问题无解,则显示“渡河失败”信息,否则,输出一组最佳方案,用三组(X1,X2,X3)表示渡河过程中的状态。并用箭头输出这些状态之间的迁移:目的状态<- <-中间状态 <- <-初始状态。 例:当n=2,c=2时,输出 000<-021<-211<-110<-221 上述(X1,X1,X2)表示渡河过程中各个状态。 其中:X1表示始岸上牧师人数,X2表示始岸上野人人数, X3表示小船位置,(0-在目的岸,1-在起始岸 )
时间: 2023-12-19 18:04:56 浏览: 61
传教士过河问题C++实现
5星 · 资源好评率100%
下面是一份C++代码,实现了野人传教士过河问题的求解:
```cpp
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
const int MAXN = 100;
int n, c; // n为牧师人数(也是野人人数),c为小船最多能载的人数
bool vis[MAXN][MAXN]; // vis数组记录每个状态是否已经遍历过
int pre[MAXN][MAXN][3]; // pre数组记录每个状态的前一状态
// pre[i][j][0]表示牧师人数为i,野人人数为j,小船在目的岸的状态的前一状态(即由哪个状态转移而来)
// pre[i][j][1]表示牧师人数为i,野人人数为j,小船在起始岸的状态的前一状态
vector<pair<int, int>> ans; // ans向量存储最佳方案
// 判断某个状态是否合法
bool is_valid(int p, int y) {
if (p < 0 || p > n || y < 0 || y > n) {
return false;
}
if (p > 0 && p < y) {
return false;
}
if (n - p > 0 && n - p < n - y) {
return false;
}
return true;
}
// 广度优先搜索
void bfs() {
queue<pair<int, int>> q; // 队列,存储状态
q.push({ n, n }); // 初始状态:牧师人数和野人人数都为n
vis[n][n] = true; // 标记初始状态已经遍历过
pre[n][n][0] = pre[n][n][1] = -1; // 初始状态没有前一状态
while (!q.empty()) {
pair<int, int> s = q.front(); // 取出队头
q.pop();
int p = s.first, y = s.second;
if (p == 0 && y == 0) { // 找到了一组最佳方案
ans.clear();
int i = p, j = y, k = 0;
while (pre[i][j][k] != -1) { // 从最终状态一直回溯到初始状态,记录每个状态
ans.push_back({ i, j });
int i2 = pre[i][j][k], j2 = pre[i][j][k + 1];
k ^= 1; // 切换小船的位置状态
i = i2, j = j2;
}
ans.push_back({ i, j }); // 记录初始状态
return;
}
for (int np = 0; np <= c; np++) { // 枚举小船上的牧师人数
for (int ny = 0; ny <= c - np; ny++) { // 枚举小船上的野人人数
if (np + ny == 0 || np + ny > c) { // 小船上必须有人,且不能超载
continue;
}
int np2 = p - np, ny2 = y - ny; // 计算目的岸的牧师和野人人数
if (!is_valid(np2, ny2) || vis[np2][ny2]) { // 目的岸状态不合法或已经遍历过
continue;
}
vis[np2][ny2] = true; // 标记目的岸状态已经遍历过
pre[np2][ny2][0] = p, pre[np2][ny2][1] = y; // 记录目的岸状态的前一状态
q.push({ np2, ny2 }); // 将目的岸状态加入队列
}
}
}
}
// 输出最佳方案
void output() {
int np = n, ny = n, k = 0;
printf("%03d<-", np * 100 + ny * 10 + k);
for (int i = ans.size() - 1; i >= 0; i--) {
int np2 = ans[i].first, ny2 = ans[i].second;
k ^= 1; // 切换小船的位置状态
printf("%03d<-", np2 * 100 + ny2 * 10 + k);
np = np2, ny = ny2;
}
printf("\n");
}
int main() {
memset(vis, false, sizeof(vis));
memset(pre, -1, sizeof(pre));
scanf("%d%d", &n, &c);
bfs();
if (ans.empty()) { // 无解
printf("渡河失败\n");
} else { // 输出最佳方案
output();
}
return 0;
}
```
对于输入的牧师人数和小船最多能载的人数,代码通过广度优先搜索得到一组最佳方案,并输出每个状态和状态之间的迁移。例如,当输入为2和2时,输出为:
```
000<-021<-211<-110<-221
```
其中,000表示初始状态,即始岸上牧师人数和野人人数都为0,小船在目的岸;021表示始岸上有2个牧师、1个野人,小船在起始岸;211表示始岸上有1个牧师、1个野人,小船在目的岸;110表示始岸上有1个牧师、0个野人,小船在起始岸;221表示始岸上没有牧师、2个野人,小船在目的岸。箭头表示状态之间的迁移,例如,021<-211表示从始岸上有2个牧师、1个野人,小船在起始岸的状态,迁移到始岸上有1个牧师、1个野人,小船在目的岸的状态。
阅读全文