本篇文章中所有數據結構都是后期整理的,如有問題歡迎指正,轉載請注明出處http://www.cnblogs.com/a1982467767/p/8889683.html
農夫過河問題
1、 問題描述:
設有一個農夫帶一只狼,一只羊和一筐菜來到河邊,打算乘一只船從右岸渡到左岸去.該船的負載能力為農夫每次只能帶一樣東西過河.在無農夫的時候,狼和羊不能在一起,羊和菜不能在一起.設計一個方案,使農夫可以無損失地渡過河.
2、 設計思路:
設計好圖的結構,點以(農夫,狼,羊,菜)表示,設置圖的點集,邊集,點數,邊數;
用is_safe函數確定圖中各點是否安全,將不安全的點去掉,剩下安全的點,然后判斷兩點之間是否可變換,再通過層次遍歷找到路徑,設定好參數,打印出路徑;
3、 代碼實現:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<windows.h> 4 #define MaxVertexNum 16 5 6 typedef struct{ 7 int farmer; 8 int wolf; 9 int sheep; 10 int vegetable; 11 }VertexType;//四元組 12 13 typedef struct{ 14 VertexType vertexs[MaxVertexNum];//頂點表表示點集 15 int edges[MaxVertexNum][MaxVertexNum];//以鄰接矩陣表示邊集 16 int vertexNum, edgeNum;//點數,邊數 17 }MGraph;//是以鄰接矩陣存儲的圖類型 18 19 typedef enum{False,Ture} Boolean; 20 21 Boolean visited[MaxVertexNum];//對已經訪問的點進行標記 22 int path[MaxVertexNum];//保存DFS搜索的路徑,即某頂點到下一個頂點的路徑 23 24 int Locate(MGraph * G, int F, int W, int S, int V) 25 { 26 //查找頂點(F,W,S,V)在頂點向量中的位置 27 int i; 28 for (i = 0; i < G->vertexNum; i++) 29 if (G->vertexs[i].farmer == F && G->vertexs[i].wolf == W && 30 G->vertexs[i].sheep == S && G->vertexs[i].vegetable == V) 31 return (i);//返回當前位置 32 return -1;//沒有查找到此頂點 33 } 34 int Is_safe(int F, int W, int S, int V) 35 {//當農夫與羊不在一起時,狼和羊 或 羊和白菜在一起是不安全的 36 if (F != S && (W == S || S == V)) return 0; 37 else return 1;//否則返回安全 38 } 39 40 //狀態是否可轉換,條件是農夫狀態不同,物品至多一項不同 41 int Is_connected(MGraph *G, int i, int j) 42 {//判斷i和j的狀態是否可以轉換 43 int k = 0; 44 if (G->vertexs[i].wolf != G->vertexs[j].wolf) k++; 45 if (G->vertexs[i].sheep != G->vertexs[j].sheep) k++; 46 if (G->vertexs[i].vegetable != G->vertexs[j].vegetable) k++; 47 if (G->vertexs[i].farmer != G->vertexs[j].farmer && k <= 1) 48 //以上三個條件不同時滿足且農夫狀態改變時,返回真,即農夫每次只能帶一件東西過河 49 return 1; 50 else return 0; 51 } 52 53 void CreateG(MGraph *G) 54 { 55 int i, j, F, W, S, V; 56 i = 0; 57 for (F = 0; F <= 1; F++) //通過安全監測函數,生成所有安全圖的頂點 58 for (W = 0; W <= 1; W++) 59 for (S = 0; S <= 1;S++) 60 for (V = 0; V <= 1;V++) 61 if (Is_safe(F, W, S, V)) 62 { 63 G->vertexs[i].farmer = F; 64 G->vertexs[i].wolf = W; 65 G->vertexs[i].sheep = S; 66 G->vertexs[i].vegetable = V; 67 i++; 68 } 69 G->vertexNum = i;//安全點數 70 for (i = 0; i < G->vertexNum; i++) 71 for (j = 0; j < G->vertexNum; j++) 72 if (Is_connected(G, i, j))//狀態i與狀態j之間可轉化,初始值為1,否則為0 73 G->edges[i][j] = G->edges[j][i] = 1; 74 else 75 G->edges[i][j] = G->edges[j][i] = 0; 76 return; 77 } 78 void Print_Path(MGraph *G, int u, int v) 79 //輸出從u到v的簡單路徑,即頂點序列中不重復出現的路徑 80 { 81 int k; 82 k = u; 83 printf("顯示右岸已經過河的物體(農夫,狼,羊,菜)\n"); 84 while (k != v)//可達的情況下,以狀態是否相同為依據,打印到達前的所有狀態 85 { 86 printf("(%d,%d,%d,%d)\n", G->vertexs[k].farmer, G->vertexs[k].wolf, 87 G->vertexs[k].sheep, G->vertexs[k].vegetable); 88 k = path[k]; 89 } 90 //打印到達的狀態 91 printf("(%d,%d,%d,%d)\n", G->vertexs[k].farmer, G->vertexs[k].wolf, 92 G->vertexs[k].sheep, G->vertexs[k].vegetable); 93 } 94 95 void Print_Graph(MGraph *G, int u, int v) 96 {//輸出從u到v的簡單可視 97 int k; 98 k = u; 99 while (k != v) 100 { 101 Sleep(1500); 102 system("cls"); 103 printf("左岸 || || 右岸\n"); 104 printf("-----++--------++-----\n"); 105 if (G->vertexs[k].farmer == 0) printf("農夫 || || \n"); 106 else printf(" || || 農夫\n"); 107 if (G->vertexs[k].wolf == 0) printf(" 狼 || 河 || \n"); 108 else printf(" || 河 || 狼\n"); 109 if (G->vertexs[k].sheep == 0) printf(" 羊 || || \n"); 110 else printf(" || || 羊\n"); 111 if (G->vertexs[k].vegetable == 0) printf("蔬菜 || || \n"); 112 else printf(" || || 蔬菜\n"); 113 k = path[k]; 114 } 115 Sleep(1500); 116 system("cls"); 117 printf("左岸 || || 右岸\n"); 118 printf("-----++--------++-----\n"); 119 printf(" || || 農夫\n"); 120 printf(" || 河 || 狼\n"); 121 printf(" || || 羊\n"); 122 printf(" || || 蔬菜\n"); 123 printf("農夫的物品已安全過河...\n"); 124 } 125 void DFS_path(MGraph *G, int u, int v) 126 //深度優先搜索從u到v的簡單路徑 127 { 128 int j; 129 visited[u] = Ture;//標志已訪問的頂點,即1 130 for (j = 0; j < G->vertexNum;j++) 131 if (G->edges[u][j] && !visited[j] && !visited[v]) 132 { 133 //鄰接矩陣中存在u、j兩點的路徑,且j、v沒有被訪問 134 path[u] = j; 135 DFS_path(G, j, v); 136 } 137 } 138 int main() 139 { 140 int i, j; 141 MGraph graph; 142 CreateG(&graph); 143 for (i = 0; i < graph.edgeNum; i++) visited[i] = False;//0表示沒有訪問,即置初值 144 i = Locate(&graph, 0, 0, 0, 0);//定位i在圖存儲中的位置 145 j = Locate(&graph, 1, 1, 1, 1);//定位j在圖存儲中的位置 146 DFS_path(&graph, i, j); 147 if (visited[j]) 148 { 149 Print_Path(&graph, i, j); 150 printf("1.5秒后打印路徑...\n"); 151 Print_Graph(&graph, i, j); 152 153 } 154 system("pause"); 155 return 0; 156 }
1、 實驗結果:
........
5、 心得體會:
通過兩周的課程設計,我學會了如何寫一個精簡、快速、健壯的程序。一個好的程序應該是一個所占空間小、運行時間短、其他性能也好的程序。而要做出一個好的程序則應該通過對算法與其數據結構的時間復雜度和空間復雜度進行實現與改進。然而,實際上很難做到十全十美,原因是各要求有時相互抵觸,要節約算法的執行時間往往要以犧牲更多的存儲空間為代價:而為了節省存儲空間又可能要以更多的時間為代價。因此,只能根據具體情況有所側重:如果程序的使用次數較少,則應該力求算法簡明易懂,而易於轉換為上機程序;如果程序反復多次使用,則應該盡可能選用快速算法;如果解決問題的數據量極大,機器的內存空間較小,則在編寫算法時應該考慮如何節省空間。 本次課程設計培養了了我們獨立思考的能力,提高了我們的動手操作水平。在具體設計操作中,我們鞏固了本學期所學的數據結構與算法的理論知識,進一步提高了自己的編程能力。這也是課程設計的最終目的所在。通過實際操作,開發了自己的邏輯思維能力,培養了分析問題、解決問題的能力。 但在程序設計的過程中我也深刻的感受到自己實力的不足,無法靈活的運用各種工具和函數,對於課程所講的東西也無法在脫離課本的情況中完成,我意識到自己在今后的學習生活中,一定要勤於思考,扎實掌握理論知識,靈活運用課上所學的東西,做一個優秀的程序員。