題目描述:農夫需要把狼、羊、菜和自己運到河對岸去,只有農夫能夠划船,而且船比較小,除農夫之外每次只能運一種東西,還有一個棘手問題,就是如果沒有農夫看着,羊會偷吃菜,狼會吃羊。請考慮一種方法,讓農夫能夠安全地安排這些東西和他自己過河。
想這個問題一連想了好幾天,本人沒有系統的學過算法,有些概念也不是很清楚,只因解決問題為目標。
嘗試過圖論解決,但用floyed算法只能算出最短路徑值,如何輸出過程,一直沒想出好的解決方法。
然后看了下面這篇文章,嘗試拋棄圖論,用樹的思想來解決這個問題。建議閱讀下面代碼時,先看看這篇文章。
參考資料:http://blog.csdn.net/orbit/article/details/7563220
在寫代碼時,本人采用了上述文章中的思想,又借鑒了圖論中存儲結點的一些方法。
我覺得這樣寫應該非常容易看懂了。具體思路見代碼。
1 #include <stdio.h> 2 #define INF 9999 3 //8個動作 4 char *action[8]={"農夫單獨過河","農夫帶狼過河","農夫帶羊過河","農夫帶菜過河", 5 "農夫單獨返回","農夫帶狼返回","農夫帶羊返回","農夫帶菜返回"}; 6 //10種狀態 7 char *state[10]={"人狼羊菜","人狼羊","人狼菜","人羊菜","人羊","狼菜","狼","羊","菜","空"}; 8 9 //狀態轉換規則:GA[i][j]=k 表示【狀態i】可以通過【動作k】轉換到【狀態j】,GA[i][j]=INF表示不可直接轉換 10 int GA[10][10]={INF,INF,INF,INF,INF, 2,INF,INF,INF,INF, 11 INF,INF,INF,INF,INF,INF, 2, 1,INF,INF, 12 INF,INF,INF,INF,INF, 0, 3,INF, 1,INF, 13 INF,INF,INF,INF,INF,INF,INF, 3, 2,INF, 14 INF,INF,INF,INF,INF,INF,INF, 0,INF, 2, 15 6,INF, 4,INF,INF,INF,INF,INF,INF,INF, 16 INF, 6, 7,INF,INF,INF,INF,INF,INF,INF, 17 INF, 5,INF, 7, 4,INF,INF,INF,INF,INF, 18 INF,INF, 5, 6,INF,INF,INF,INF,INF,INF, 19 INF,INF,INF,INF, 6,INF,INF,INF,INF,INF}; 20 21 //記錄每一步的動作 22 int record_action[20]; 23 //記錄每一步動作后的狀態 24 int record_state[20]; 25 26 //搜索從第step步開始、第i個結點到第n個結點的過程(step從0算起) 27 void search(int i,int n,int step) 28 { 29 int k;//動作 30 int j;//可能要轉換到的狀態 31 if(i==n) 32 { 33 for(k=0;k<step;k++) 34 printf("step %d: %s,左岸還剩 %s\n",k+1,action[record_action[k]],state[record_state[k]]); 35 printf("step count:%d\n\n",step); 36 return; 37 } 38 //查找在當前【狀態i】下能轉換到的【其它狀態j】,並且【狀態j】不能在之前出現過 39 //查找時可能會出現多個 j,所以這是一個多叉樹 40 for(k=0;k<8;k++) 41 { 42 for(j=0;j<10;j++) 43 if(GA[i][j]!=INF&&GA[i][j]==k)//判斷狀態i能否通過動作k轉換到狀態j 44 { 45 int m; 46 //下面這個循環是判斷狀態j在之前是否出現過 47 for(m=0;m<step;m++) 48 if(j==record_state[m])break; 49 if(m<step)continue; 50 //如果j滿足前面所有條件,則記錄這一步 51 record_action[step]=k; //第step步所使用的動作 52 record_state[step]=j; //第step步所轉換的狀態 53 search(j,n,step+1); //繼續搜索下一步 54 } 55 } 56 57 } 58 int main() 59 { 60 search(0,9,0); 61 return 0; 62 }