請幫助一家五口在黑夜中過河。
注意事項:
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
黑夜過橋問題是可遞迴解的
沒有留言:
張貼留言