C語言實現農夫過河程式碼及解析
問題描述
一個農夫在河邊帶了一隻狼、一隻羊和一顆白菜,他需要把這三樣東西用船帶到河的對岸。然而,這艘船隻能容下農夫本人和另外一樣東西。如果農夫不在場的話,狼會吃掉羊,羊也會吃掉白菜。請程式設計為農夫解決這個過河問題。
問題分析
根據問題描述可知,該問題涉及的物件較多,而且運算步驟也較為複雜,因此,在使用C語言實現時,首先需要將具體問題數字化。
由於整個過程的實現需要多步,而不同步驟中各個事物所處的位置不同,因此可以定義一個二維陣列或者結構體來表不四個物件狼(wolf)、羊(goat)、白菜(cabbage)和農夫(farmer)。對於東岸和西岸,可以用east和west表示,也可以用0和1來表示, 以保證在程式設計中的簡便性。
題目要求給出四種事物的過河步驟,沒有對先後順序進行約束,這就需要給各個事物依次進行編號,然後依次試探,若試探成功,再進行下一步試探。因此,解決該問題可以使用迴圈或者遞迴演算法,以避免隨機盲目運算而且保證每種情況都可以試探到。
題目要求求出農夫帶一隻羊,一條狼和一顆白菜過河的所有辦法,所以依次成功返回運算結果後,需要繼續運算,直至求出所有結果,即給出農夫不同的過河方案。
演算法設計
本程式使用遞迴演算法,定義二維陣列int a[N][4]儲存每一步中各個事物所處的位置。二維陣列的一維下標表示當前進行的步驟,第二維下標可能的取值為0〜3,在這裡規定它與四種事物的具體對應關係為:0——狼、1——羊、2——白菜、3——農夫。接著再將東岸和西岸數字化,用0表示東岸,1表示西岸,該資訊儲存在二維陣列的對應元素中。
定義Step變量表示渡河的步驟,則成功渡河之後,a陣列中的儲存狀態為:
a[Step][0] 1
a[Step][1] 1
a[Step][2] 1
a[Step][3] 1
因為成功渡河後,狼、羊、白菜和農夫都在河的西岸,因此有:
a[Step][0]+a[Step][1]+a[Step][2]+a[Step][3]=4
題目中要求狼和羊、羊和白菜不能在一起,因此若有下述情況出現:
a[Step][1]!=a[Step][3] && (a[Step][2]==a[Step][1] || a[Step][0]=a[Step][1])
則發生錯誤,應返回操作。
在程式實現時,除了定義a陣列來儲存每一步中各個物件所處的位置以外,再定義一維陣列b[N]來儲存每一步中農夫是如何過河的。
程式中實現遞迴操作部分的核心程式碼為:
for(i=-1; i<=2; i++)
{
b[Step]=i;
memcpy(a[Step+1], a[Step], 16); /*複製上一步狀態,進行下一步移動*/
a[Step+1][3]=1-a[Step+1][3]; /*農夫過去或者回來*/
if(i == -1)
{
search(Step+1); /*進行第一步*/
}
else
if(a[Step][i] == a[Step][3]) /*若該物與農夫同岸,帶回*/
{
a[Step+1][i]=a[Step+1][3]; /*帶回該物*/
search(Step+1); /*進行下一步*/
}
}
每次迴圈從-1到2依次代表農夫渡河時為一人、帶狼、帶羊、帶白菜通過,利用語句“b[Step] = i”分別記錄每一步中農夫的渡河方式,語句“a[Step+1][i] = a[Step+1][3]”是利用賦值方式使該物件與農夫一同到對岸或者回到本岸。若渡河成功,則依次輸出渡河方式。“i<=2”為遞迴操作的界限,若i=2時仍無符合條件的方式,則渡河失敗。
上面程式碼表示若當前步驟能使各值均為1,則渡河成功,輸出結果,進入迴歸步驟。若當前步驟與以前的步驟相同,則返回操作,程式碼如下:
if(memcmp(a[i],a[Step],16) == 0)
{
return 0;
}
若羊和農夫不在一塊而狼和羊或者羊和白菜在一塊,則返回操作,判斷程式碼如下:
if(a[Step][1]!=a[Step][3] && (a[Step][2] == a[Step][1] || a[Step][0] == a[Step][1]))
{
return 0;
}
下面是完整的程式碼:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 15
int a[N][4];
int b[N];
char *name[]=
{
" ",
"and wolf",
"and goat",
"and cabbage"
};
int search(int Step)
{
int i;
/*若該種步驟能使各值均為1,則輸出結果,進入迴歸步驟*/
if(a[Step][0]+a[Step][1]+a[Step][2]+a[Step][3] == 4)
{
for(i=0; i<=Step; i++) /*能夠依次輸出不同的方案*/
{
printf("east: ");
if(a[i][0] == 0)
printf("wolf ");
if(a[i][1] == 0)
printf("goat ");
if(a[i][2] == 0)
printf("cabbage ");
if(a[i][3] == 0)
printf("farmer ");
if(a[i][0] && a[i][1] && a[i][2] && a[i][3])
printf("none");
printf(" ");
printf("west: ");
if(a[i][0] == 1)
printf("wolf ");
if(a[i][1] == 1)
printf("goat ");
if(a[i][2] == 1)
printf("cabbage ");
if(a[i][3] == 1)
printf("farmer ");
if(!(a[i][0] || a[i][1] || a[i][2] || a[i][3]))
printf("none");
printf("\n\n\n");
if(i<Step)
printf(" the %d time\n",i+1);
if(i>0 && i<Step)
{
if(a[i][3] == 0) /*農夫在本岸*/
{
printf(" -----> farmer ");
printf("%s\n", name[b[i] + 1]);
}
else /*農夫在對岸*/
{
printf(" <----- farmer ");
printf("%s\n", name[b[i] + 1]);
}
}
}
printf("\n\n\n\n");
return 0;
}
for(i=0; i<Step; i++)
{
if(memcmp(a[i],a[Step],16) == 0) /*若該步與以前步驟相同,取消操作*/
{
return 0;
}
}
/*若羊和農夫不在一塊而狼和羊或者羊和白菜在一塊,則取消操作*/
if(a[Step][1]!=a[Step][3] && (a[Step][2] == a[Step][1] || a[Step][0] == a[Step][1]))
{
return 0;
}
/*遞迴,從帶第一種動物開始依次向下迴圈,同時限定遞迴的界限*/
for(i=-1; i<=2; i++)
{
b[Step]=i;
memcpy(a[Step+1], a[Step], 16); /*複製上一步狀態,進行下一步移動*/
a[Step+1][3]=1-a[Step+1][3]; /*農夫過去或者回來*/
if(i == -1)
{
search(Step+1); /*進行第一步*/
}
else
if(a[Step][i] == a[Step][3]) /*若該物與農夫同岸,帶回*/
{
a[Step+1][i]=a[Step+1][3]; /*帶回該物*/
search(Step+1); /*進行下一步*/
}
}
return 0;
}
int main()
{
printf("\n\n 農夫過河問題,解決方案如下:\n\n\n");
search(0);
return 0;
}
執行結果:
農夫過河問題,解決方案如下:
east: wolf goat cabbage farmer west: none
the 1 time
east: wolf cabbage west: goat farmer
the 2 time
<----- farmer
east: wolf cabbage farmer west: goat
the 3 time
-----> farmer and wolf
east: cabbage west: wolf goat farmer
the 4 time
<----- farmer and goat
east: goat cabbage farmer west: wolf
the 5 time
-----> farmer and cabbage
east: goat west: wolf cabbage farmer
the 6 time
<----- farmer
east: goat farmer west: wolf cabbage
the 7 time
-----> farmer and goat
east: none west: wolf goat cabbage farmer
east: wolf goat cabbage farmer west: none
the 1 time
east: wolf cabbage west: goat farmer
the 2 time
<----- farmer
east: wolf cabbage farmer west: goat
the 3 time
-----> farmer and cabbage
east: wolf west: goat cabbage farmer
the 4 time
<----- farmer and goat
east: wolf goat farmer west: cabbage
the 5 time
-----> farmer and wolf
east: goat west: wolf cabbage farmer
the 6 time
<----- farmer
east: goat farmer west: wolf cabbage
the 7 time
-----> farmer and goat
east: none west: wolf goat cabbage farmer