請幫助一家五口在黑夜中過河。
注意事項:
1.因為是黑夜,他們必須帶備燈。
2.每位家庭成員都有不同的速度過橋,由1秒、3秒、6秒、8秒、到12秒。
3.橋只可最多承受2人的重量。
4.當2人同時在橋上行走,速度必跟隨較慢的一位。
5.燈只足夠維持30秒。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
const int TARGET_STATE = 64-1; // 111 111b
vector<int> crossSnapshot;
vector<int> takerSnapshot;
void showPauseMsg();
enum{
lamp=32,
m12=16,
m8=8,
m6=4,
m3=2,
m1=1
};
int cross[] = {
m12, m8, m6, m3, m1,
m12|m8, m12|m6, m12|m3, m12|m1,
m8|m6, m8|m3, m8|m1,
m6|m3, m6|m1,
m3|m1
};
int crossCost[]={
12, 8, 6, 3, 1,
12, 12, 12, 12,
8,8,8,
6,6,
3
};
int crossUppIdx = (sizeof(cross)/ sizeof(int))-1;
void printState(int iState){
//print out Bit N, N start from 0
int N=8;
for(int i=N-1;i>=0;i--)
{
cout << ((iState >> i ) & 1);//show Bit 3
}
cout << endl;
}
//get a binary digit N of iNumber, N start from Right to Left
// Rightmost is 1
//return 0 or 1, Bit N at iNumber
int getBitN(int iNumber, int N){
return (iNumber >> (N-1)) & 1;
}
int getLampState (int iState){ return getBitN(iState, 6);}
bool isSafe(vector<int> &takerSnapshot, int addCost){
int sum =0;
for(int j=0; j<takerSnapshot.size();j++){
sum += crossCost[takerSnapshot[j]];
}
sum += addCost;
if (sum >30){ return false;}
return true;
}
bool isTry(int state){
bool isTried = false;
for(int j=0; j < crossSnapshot.size();j++){
if (state == crossSnapshot[j]){
isTried = true;
break;
}
}
return isTried;
}
void printTaker(int i){
char* msg[] = {
"12", "8", "6", "3", "1",
"(12,8)", "(12,6)", "(12,3)", "(12,1)",
"(8,6)", "(8,3)", "(8,1)",
"(6,3)", "(6,1)",
"(3,1)"
};
if(i >= 0 && i <= crossUppIdx) {
cout << msg[i] << endl;
}
}
string getTaker(int i){
char* msg[] = {
"12", "8", "6", "3", "1",
"(12,8)", "(12,6)", "(12,3)", "(12,1)",
"(8,6)", "(8,3)", "(8,1)",
"(6,3)", "(6,1)",
"(3,1)"
};
if(i >= 0 && i <= crossUppIdx) {
return string(msg[i]);
}
return string("");
}
void printEveryBitState(vector<int> &crossSnapshot){
cout << "total number cross state = " << crossSnapshot.size()<<endl;
for(int j=0; j < crossSnapshot.size();j++){
printState(crossSnapshot[j]);
}
}
void printEveryWordState(vector<int> &takerSnapshot){
cout << "The cross step is show as belowing." << endl;
for(int j=0; j < takerSnapshot.size();j++){
cout << j+1 << ". ";
cout << getTaker(takerSnapshot[j]);
if (j%2 == 0){
cout << " <---" << endl;
} else {
cout << " --->"<< endl;
}
}
//add a dummy blank line
cout <<endl;
}
void printTotalMins(vector<int> &takerSnapshot){
int totalMins = 0;
for(int j=0; j < takerSnapshot.size();j++){
totalMins += crossCost[takerSnapshot[j]];
}
cout << "total mins used = " << totalMins << endl;
}
void recordTriedState(int state, int i, vector<int> &crossSnapshot){
//save snapshot
crossSnapshot.push_back(state);
takerSnapshot.push_back(i);
}
void RollbackRecordState(int state, vector<int> &crossSnapshot){
//delete previous snapshot
//cout << "roll back ...." << endl << endl;
//printEveryWordState(takerSnapshot);
//printEveryBitState(crossSnapshot);
crossSnapshot.pop_back();
takerSnapshot.pop_back();
}
bool isMoverSameSideWithBoat(int currentState, int mover){
bool rv = false;
int lampState = getLampState(currentState);
if(lampState==0)
{
if ((currentState & mover) == 0){ rv = true; }
}
else
{
if ((currentState & mover)== mover){ rv = true; }
}
return rv;
}
void crossRiver(int state,
vector<int> &crossSnapshot)
{
if (state == TARGET_STATE){
//printEveryBitState(crossSnapshot);
printEveryWordState(takerSnapshot);
printTotalMins(takerSnapshot);
//stop recurive iteration
showPauseMsg(); // if u want to print similarly answer, hide this code
exit(0); // if u want to print similarly answer, hide this code
return;
}
//for every cross choice
for(int i=0; i<=crossUppIdx; i++){
int mover = cross[i];
bool isMoverSameWithBoat = isMoverSameSideWithBoat(state, mover);
// if mover object is not same side as boat
if (!isMoverSameWithBoat){
continue;
}
int nextCrossState = (state ^ mover) ^ lamp; // use bitwise^ to toggle the Bit i
bool isSafed = isSafe(takerSnapshot, crossCost[i]);
bool isNotTry = (!isTry(nextCrossState));
if( isSafed && isNotTry ){
//printState(nextCrossState);
//printTaker(i);
//int x = takerSnapshot.size();
recordTriedState(nextCrossState, i, crossSnapshot);
//recurive to call itself
crossRiver(nextCrossState, crossSnapshot);
RollbackRecordState(nextCrossState, crossSnapshot);
}
}
}
void showPauseMsg(){
cout << "Press any key to be continue" << endl;
getchar();
}
int main() {
//save first snapshot
crossSnapshot.push_back(0);
crossRiver(0, crossSnapshot);
//showPauseMsg();
return 0;
}
The cross step is show as belowing.1. (6,1) <---
2. 1 --->
3. (3,1) <---
4. 3 --->
5. (12,8) <---
6. 1 --->
7. (3,1) <---
total mins used = 29
Press any key to be continue
延伸閱讀:
其他人的文章,如果是 N個人一共只帶了一只手電筒等變形問題的版本
http://blog.csdn.net/wuzhekai1985/article/details/6846934
http://renren.it/a/bianchengyuyan/_NET/20111006/133147.html
黑夜過橋問題是可遞迴解的
沒有留言:
張貼留言