用c++的回溯法写一个一个猎人带着一只狼、一头羊和一筐青菜欲乘一独木舟渡河,因独木舟太小,猎人一次至多只能带狼、羊或青菜之一渡河,但当与猎人不在河的同一边时,狼会吃掉羊、羊会吃掉青菜。试设计一个算法,帮猎人寻找一种渡河的次序让其不受损失地将狼、羊和青菜带过河去的代码
时间: 2024-02-17 12:00:38 浏览: 69
下面是一个使用回溯法解决这个问题的示例代码:
```
#include <iostream>
#include <vector>
#include <unordered_set>
using namespace std;
const int BOAT_CAPACITY = 2; // 独木舟的容量为2
const int LEFT_BANK = 0; // 左岸
const int RIGHT_BANK = 1; // 右岸
unordered_set<string> visited; // 记录已经遍历过的状态
bool isValid(int wolf, int sheep, int vegetable) {
if (wolf == sheep && wolf != BOAT_CAPACITY) { // 狼会吃掉羊
return false;
}
if (sheep == vegetable && sheep != BOAT_CAPACITY) { // 羊会吃掉青菜
return false;
}
return true;
}
void dfs(int wolf, int sheep, int vegetable, int boat, vector<int>& path, vector<vector<int>>& result) {
if (wolf == BOAT_CAPACITY && sheep == BOAT_CAPACITY && vegetable == BOAT_CAPACITY && boat == RIGHT_BANK) { // 所有物品都已经运输到右岸
result.push_back(path);
return;
}
string state = to_string(wolf) + to_string(sheep) + to_string(vegetable) + to_string(boat);
if (visited.count(state)) { // 如果这个状态已经遍历过了,直接返回
return;
}
visited.insert(state);
if (boat == LEFT_BANK) { // 如果独木舟在左岸
if (wolf < BOAT_CAPACITY) { // 狼可以乘船过河
for (int i = 1; i <= BOAT_CAPACITY; i++) {
if (i <= wolf) continue; // 如果狼已经在船上了,就不需要再放一次了
if (!isValid(wolf+i, sheep, vegetable)) continue;
path.push_back(i);
dfs(wolf+i, sheep, vegetable, RIGHT_BANK, path, result);
path.pop_back();
}
}
if (sheep < BOAT_CAPACITY) { // 羊可以乘船过河
for (int i = 1; i <= BOAT_CAPACITY; i++) {
if (i <= sheep) continue;
if (!isValid(wolf, sheep+i, vegetable)) continue;
path.push_back(-i);
dfs(wolf, sheep+i, vegetable, RIGHT_BANK, path, result);
path.pop_back();
}
}
if (vegetable < BOAT_CAPACITY) { // 青菜可以乘船过河
for (int i = 1; i <= BOAT_CAPACITY; i++) {
if (i <= vegetable) continue;
if (!isValid(wolf, sheep, vegetable+i)) continue;
path.push_back(i);
dfs(wolf, sheep, vegetable+i, RIGHT_BANK, path, result);
path.pop_back();
}
}
} else { // 如果独木舟在右岸
if (wolf == BOAT_CAPACITY) { // 狼可以乘船过河
for (int i = 1; i <= BOAT_CAPACITY; i++) {
if (i <= wolf) continue;
if (!isValid(wolf-i, sheep, vegetable)) continue;
path.push_back(-i);
dfs(wolf-i, sheep, vegetable, LEFT_BANK, path, result);
path.pop_back();
}
}
if (sheep == BOAT_CAPACITY) { // 羊可以乘船过河
for (int i = 1; i <= BOAT_CAPACITY; i++) {
if (i <= sheep) continue;
if (!isValid(wolf, sheep-i, vegetable)) continue;
path.push_back(i);
dfs(wolf, sheep-i, vegetable, LEFT_BANK, path, result);
path.pop_back();
}
}
if (vegetable == BOAT_CAPACITY) { // 青菜可以乘船过河
for (int i = 1; i <= BOAT_CAPACITY; i++) {
if (i <= vegetable) continue;
if (!isValid(wolf, sheep, vegetable-i)) continue;
path.push_back(-i);
dfs(wolf, sheep, vegetable-i, LEFT_BANK, path, result);
path.pop_back();
}
}
}
visited.erase(state);
}
int main() {
vector<vector<int>> result;
vector<int> path;
dfs(0, 0, 0, LEFT_BANK, path, result); // 从左岸开始
cout << "There are " << result.size() << " valid routes:" << endl;
for (auto& r : result) {
for (auto& p : r) {
if (p > 0) {
cout << " + ";
} else {
cout << " - ";
}
if (abs(p) == BOAT_CAPACITY) {
cout << "wolf/sheep/vegetable";
} else if (abs(p) == 1) {
cout << "wolf";
} else if (abs(p) == 2) {
cout << "sheep";
} else if (abs(p) == 3) {
cout << "vegetable";
}
}
cout << endl;
}
return 0;
}
```
在这个示例代码中,函数 `dfs` 使用回溯法来找到所有可能的运输方案。函数的参数包括当前状态下狼、羊、青菜的位置,船的位置,已经运输的路径,以及所有的运输方案。函数首先判断当前状态是否已经遍历过,如果是,则直接返回。然后,函数根据当前船的位置,枚举可以乘船过河的动物,以及每次可以运输的数量。在运输过程中,需要检查新状态是否合法,即狼会不会吃掉羊,羊会不会吃掉青菜。如果当前状态是一个合法的终止状态,则将当前的运输路径加入到所有运输方案中。最后,函数返回所有运输方案。
在主函数中,我们调用 `dfs` 函数,从左岸开始,得到所有可能的运输方案。我们可以遍历这些方案,输出每次运输的动物或物品即可。
阅读全文