農夫が川を渡る問題C++再帰実現
4320 ワード
ある農夫は狼と羊と白菜を連れて、川の南岸にいた.彼はこれを
いくつかのものはすべて北岸に運ばれた.彼の前にはボートが1隻しかないので,船は彼と荷物を収容するしかない.
品物、それから農夫だけが船を支えることができます.農夫がその場にいたら、狼は羊を食べられず、羊は食べられない.
白菜を食べて、さもなくばオオカミは羊を食べて、羊は白菜を食べて、だから農夫は羊と白菜を残してはいけません
自分が離れても、オオカミと羊を残して自分で離れてはいけない.オオカミは白菜を食べない.農夫将を出すように頼む
すべてのものが川を運ぶ案.
いくつかのものはすべて北岸に運ばれた.彼の前にはボートが1隻しかないので,船は彼と荷物を収容するしかない.
品物、それから農夫だけが船を支えることができます.農夫がその場にいたら、狼は羊を食べられず、羊は食べられない.
白菜を食べて、さもなくばオオカミは羊を食べて、羊は白菜を食べて、だから農夫は羊と白菜を残してはいけません
自分が離れても、オオカミと羊を残して自分で離れてはいけない.オオカミは白菜を食べない.農夫将を出すように頼む
すべてのものが川を運ぶ案.
/*
* Farmer cross river with wolf, sheep and cabbage
* Depth first search implementation.
* Author: ProHanziiee
* E-mail: [email protected]
* Date: 2017-11-16
*/
#include
using namespace std;
enum Item{nothing, wolf, sheep, cabbage};
map- foodChain;
map
- reverseFoodChain;
set
- sideA, sideB;
bool check(set
- s) {
for(auto &x : s) {
if(s.find(foodChain[x]) != s.end() || s.find(reverseFoodChain[x]) != s.end()) return false;
}
return true;
}
vector
- v;
map
>, pair > > trace;
pair > endPath;
bool dfs(int dir, Item item, pair > path) {
if(dir == 0) { // dir = 0 means transfer item(may be nothing) from sideA to sideB
if(item != nothing) sideB.insert(item);
if((int)sideB.size() == 3) { // Okay, all items have heen transfered from sideA to sideB
endPath = path;
return true;
}
if(check(sideB) == true) {
endPath = make_pair(path.first + 1, make_pair(1, nothing));
trace[endPath] = path;
if(dfs(1, nothing, endPath) == true) return true;
}
for(int i = 0; i < 3; ++i) {
Item tmp = v[i];
if(tmp == item || sideB.find(tmp) == sideB.end()) continue;
sideB.erase(sideB.find(tmp));
if(check(sideB) == true) {
endPath = make_pair(path.first + 1, make_pair(1, tmp));
trace[endPath] = path;
if(dfs(1, tmp, endPath) == true) return true;
}
sideB.insert(tmp);
}
sideB.erase(item);
} else { // dir = 1 means transfer item(may be nothing) from sideB to sideA
if(item != nothing) sideA.insert(item);
if(sideA.size() == 3) return false;
for(int i = 0; i < 3; ++i) {
Item tmp = v[i];
if(tmp == item || sideA.find(tmp) == sideA.end()) continue;
sideA.erase(sideA.find(tmp));
if(check(sideA) == true) {
endPath = make_pair(path.first + 1, make_pair(0, tmp));
trace[endPath] = path;
if(dfs(0, tmp, endPath) == true) return true;
}
sideA.insert(tmp);
}
}
return false;
}
void init() {
trace.clear();
sideA.clear();
sideB.clear();
foodChain.clear();
reverseFoodChain.clear();
foodChain[wolf] = sheep;
reverseFoodChain[sheep] = wolf;
foodChain[sheep] = cabbage;
reverseFoodChain[cabbage] = sheep;
v.clear();
v.push_back(wolf);
v.push_back(sheep);
v.push_back(cabbage);
}
void outputItem(Item item) {
switch(item) {
case wolf: puts("Wolf");
break;
case sheep: puts("Sheep");
break;
case cabbage: puts("Cabbage");
break;
default: puts("Nothing");
}
}
void outputDirection(int dir) {
if(dir == 0) { printf("A -> B with "); }
else { printf("B -> A with "); }
}
void outputTrace() {
puts("A is the initial side of river while B is the target side!");
while(endPath != make_pair(-1, make_pair(-1, nothing))) {
outputDirection(endPath.second.first);
outputItem(endPath.second.second);
endPath = trace[endPath];
}
}
int main() {
#ifdef Zonda_R
freopen("data.in", "r", stdin);
freopen("data.out", "w", stdout);
#endif
init();
sideA.insert(wolf);
sideA.insert(sheep);
sideA.insert(cabbage);
bool valid = false;
for(int i = 0; i < 3; ++i) {
Item tmp = v[i];
if(sideA.find(tmp) != sideA.end()) {
sideA.erase(sideA.find(tmp));
if(check(sideA) == true) {
trace.clear();
endPath = make_pair(0, make_pair(0, tmp));
trace[endPath] = make_pair(-1, make_pair(-1, nothing));
if(dfs(0, tmp, endPath) == true) {
valid = true;
break;
}
}
sideA.insert(tmp);
}
}
if(valid == true) {
outputTrace();
} else {
puts("No Solution!");
}
return 0;
}