問題描述:
游戲的規則是這樣的:將一副撲克牌平均分成兩份,每人拿一份。小哼先拿出手中的第一張撲克牌放在桌上,然后小哈也拿出手中的第一張撲克牌,並放在小哼剛打出的撲克牌的上面,就像這樣兩人交替出牌。出牌時,如果某人打出的牌與桌上某張牌的牌面相同,即可將兩張相同的牌及其中間所夾的牌全部取走,並依次放到自己手中牌的末尾。當任意一人手中的牌全部出完時,游戲結束,對手獲勝。
假如游戲開始時,小哼手中有6 張牌,順序為2 4 1 2 5 6,小哈手中也有6 張牌,順序為3 1 3 5 6 4,最終誰會獲勝呢?現在你可以拿出紙牌來試一試。接下來請你寫一個程序來自動判斷誰將獲勝。這里我們做一個約定,小哼和小哈手中牌的牌面只有1~9。
分析:
小哼或小哈 對應的兩個操作------出牌和贏牌,其中出牌對應於出隊,贏牌對應於入隊
桌子相當於 棧,每打出一張牌就相當於入棧,當有人贏牌時,一次將牌從桌子上拿走,相當於出棧
贏牌規則:如果某人打出的牌與桌子上的某張牌相同,即可將兩張牌及中間的牌全部取走
獲勝規則:當任意一人手中的牌全部出完時,游戲結束,對手獲勝
首先創建一個結構體用來實現隊列:
typedef struct queue{ ElementType data[MaxSize]; int head; int tail; }Queue;
接着創建棧:
typedef struct stack{ ElementType data[N]; int top; }Stack;
注:這里的N,定義的是10 ,因為桌子上最多有9章不同的牌(一旦有重復的牌就會出棧抽走),又因桌子上的數子為1~9(數組下標為0的不用),故有定義N為10 足夠
接下來定義兩個隊列變量q1和q2, q1用來模擬小哼手中的牌,q2用來模擬小哈手中的牌,定義一個棧變量s模擬桌子上的牌
Queue q1,q2;
Stack s;
再接着初始化隊列和棧
// 初始化隊列q1和q2為空,此時兩人手里都沒有牌 q1.head = 1; q1.tail = 1; q2.head = 1; q2.tail = 1; // 初始化棧s為空,最開始桌上沒有牌 s.top= 0;
接下來讀入小哼和小哈最初手上的牌,分兩次讀入,每次讀入六個數,分別插入q1和q2中
// 先讀入六張牌,分別放在小哼和小哈手上 for(i=1;i<=6;++i) { scanf("%d",&q1.data[q1.tail++]); // 讀入一個數到隊列 } for(i=1;i<=6;++i) { scanf("%d",&q2.data[q2.tail++]); // 讀入一個數到隊列 }
再判斷,小哼和小哈打出來的牌是否可以贏牌(即打出的牌跟桌子上的牌有沒有重復的),這里需要注意的事用book[N]來標記桌子上的牌數
例如先判斷小哼(或者小哈)的出牌,若小哼的這張牌在桌子上有,那么就將這張牌出隊,並放在隊尾,最后將桌子上的與此紙牌數相同的 出棧,放到小哼的隊尾,否則,小哼的出隊,放入桌子上(即入棧),並標記此紙牌。具體的代碼如下所示:
while(q1.head<q1.tail && q2.head<q2.tail) { t = q1.data[q1.head]; // 小哼先出牌 if(book[t]==0) // 表明桌上沒有牌面為t的牌 { //小哼此輪沒有贏牌 q1.head++; //小哼已經打出一張牌,所以要把打出的牌出隊 s.top++; // 進棧 s.data[s.top]=t; //再把打出的牌放到桌上,即入棧 book[t]=1; //標記桌上現在已經有牌面為t的牌 } else { //小哼此輪可以贏牌 q1.head++;//小哼已經打出一張牌,所以要把打出的牌出隊 q1.data[q1.tail]=t;//緊接着把打出的牌放到手中牌的末尾 q1.tail++; while(s.data[s.top]!=t) //把桌上可以贏得的牌依次放到手中牌的末尾 { book[s.data[s.top]]=0;//取消標記 q1.data[q1.tail]=s.data[s.top];//依次放入隊尾 q1.tail++; s.top--; //棧中少了一張牌,所以棧頂要減1 } } t=q2.data[q2.head]; //小哈出一張牌 //判斷小哈當前打出的牌是否能贏牌 if(book[t]==0) //表明桌上沒有牌面為t的牌 { //小哈此輪沒有贏牌 q2.head++; //小哈已經打出一張牌,所以要把打出的牌出隊 s.top++; s.data[s.top]=t; //再把打出的牌放到桌上,即入棧 book[t]=1; //標記桌上現在已經有牌面為t的牌 } else { //小哈此輪可以贏牌 q2.head++;//小哈已經打出一張牌,所以要把打出的牌出隊 q2.data[q2.tail]=t;//緊接着把打出的牌放到手中牌的末尾 q2.tail++; while(s.data[s.top]!=t) //把桌上可以贏得的牌依次放到手中牌的末尾 { book[s.data[s.top]]=0;//取消標記 q2.data[q2.tail]=s.data[s.top];//依次放入隊尾 q2.tail++; s.top--; } } }
最后一步,輸出誰最終贏得了游戲,以及游戲結束后獲勝者手中的牌和桌上的牌。如果小哼獲勝了那么小哈的手中一定沒有牌了(隊列q2 為空),即q2.head==q2.tail,具體輸出如下。
if(q2.head==q2.tail) // 當任意一人手中的牌全部出完時,游戲結束,對手獲勝 { printf("小哼獲勝\n"); printf("小哼當前手中的牌是"); for(i=q1.head;i<=q1.tail-1;i++) printf(" %d",q1.data[i]); if(s.top>0) //如果桌上有牌則依次輸出桌上的牌 { printf("\n桌上的牌是"); for(i=1;i<=s.top;i++) printf(" %d",s.data[i]); printf("\n"); } else printf("\n桌上已經沒有牌了"); } else { printf("小哈獲勝\n"); printf("小哈當前手中的牌是"); for(i=q2.head;i<=q2.tail-1;i++) printf(" %d",q2.data[i]); if(s.top>0) //如果桌上有牌則依次輸出桌上的牌 { printf("\n桌上的牌是"); for(i=1;i<=s.top;i++) printf(" %d",s.data[i]); printf("\n"); } else printf("\n桌上已經沒有牌了\n"); }
OK,每個過程分析完了,一下看看詳細代碼:
1 #include<stdio.h> 2 #define MaxSize 1001 3 #define N 10 4 #define ElementType int 5 6 7 /* 8 * brief:小貓釣魚問題, 轉化為棧和隊列的操作來求解 9 * input:分別輸入兩組數字,每組數字6個 大小限制在1~9之間 10 * output:獲勝一方,和桌子上剩余的紙牌 11 * example: 12 * input: 2 4 1 2 5 6 13 * 3 1 3 5 6 4 14 * output: 小哼win 15 * 小哼當前手中的牌是 5 6 2 3 1 4 6 5 16 * 桌上的牌是 2 1 3 4 17 */ 18 19 // 定義一個隊列用來模擬小哼小哈的操作 20 typedef struct queue{ 21 ElementType data[MaxSize]; 22 int head; 23 int tail; 24 }Queue; 25 26 // 定義棧用來模擬桌子的操作 27 typedef struct stack{ 28 ElementType data[N]; 29 int top; 30 }Stack; 31 32 33 int main() 34 { 35 Queue q1,q2; // q1,q2分別模擬小哼和小哈手中的牌 36 Stack s; // 模擬桌子上的牌 37 int i,t; 38 int book[N]; // 用來標記桌子上出牌的數字(1~9) 39 40 // 初始化隊列q1和q2為空,此時兩人手里都沒有牌 41 q1.head = 1; q1.tail = 1; 42 q2.head = 1; q2.tail = 1; 43 // 初始化棧s為空,最開始桌上沒有牌 44 s.top= 0; 45 // 初始化用來標記的數組,用來標記哪些牌在桌子上了 46 for(i=1;i<=9;i++) 47 book[i] = 0; 48 49 // 先讀入六張牌,分別放在小哼和小哈手上 50 for(i=1;i<=6;++i) 51 { 52 scanf("%d",&q1.data[q1.tail++]); // 讀入一個數到隊列 53 } 54 for(i=1;i<=6;++i) 55 { 56 scanf("%d",&q2.data[q2.tail++]); // 讀入一個數到隊列 57 } 58 59 while(q1.head<q1.tail && q2.head<q2.tail) 60 { 61 t = q1.data[q1.head]; // 小哼先出牌 62 if(book[t]==0) // 表明桌上沒有牌面為t的牌 63 { 64 //小哼此輪沒有贏牌 65 q1.head++; //小哼已經打出一張牌,所以要把打出的牌出隊 66 s.top++; // 進棧 67 s.data[s.top]=t; //再把打出的牌放到桌上,即入棧 68 book[t]=1; //標記桌上現在已經有牌面為t的牌 69 } 70 else 71 { 72 //小哼此輪可以贏牌 73 q1.head++;//小哼已經打出一張牌,所以要把打出的牌出隊 74 q1.data[q1.tail]=t;//緊接着把打出的牌放到手中牌的末尾 75 q1.tail++; 76 while(s.data[s.top]!=t) //把桌上可以贏得的牌依次放到手中牌的末尾 77 { 78 book[s.data[s.top]]=0;//取消標記 79 q1.data[q1.tail]=s.data[s.top];//依次放入隊尾 80 q1.tail++; 81 s.top--; //棧中少了一張牌,所以棧頂要減1 82 } 83 } 84 t=q2.data[q2.head]; //小哈出一張牌 85 //判斷小哈當前打出的牌是否能贏牌 86 if(book[t]==0) //表明桌上沒有牌面為t的牌 87 { 88 //小哈此輪沒有贏牌 89 q2.head++; //小哈已經打出一張牌,所以要把打出的牌出隊 90 s.top++; 91 s.data[s.top]=t; //再把打出的牌放到桌上,即入棧 92 book[t]=1; //標記桌上現在已經有牌面為t的牌 93 } 94 else 95 { 96 //小哈此輪可以贏牌 97 q2.head++;//小哈已經打出一張牌,所以要把打出的牌出隊 98 q2.data[q2.tail]=t;//緊接着把打出的牌放到手中牌的末尾 99 q2.tail++; 100 while(s.data[s.top]!=t) //把桌上可以贏得的牌依次放到手中牌的末尾 101 { 102 book[s.data[s.top]]=0;//取消標記 103 q2.data[q2.tail]=s.data[s.top];//依次放入隊尾 104 q2.tail++; 105 s.top--; 106 } 107 } 108 } 109 110 if(q2.head==q2.tail) // 當任意一人手中的牌全部出完時,游戲結束,對手獲勝 111 { 112 printf("小哼獲勝\n"); 113 printf("小哼當前手中的牌是"); 114 for(i=q1.head;i<=q1.tail-1;i++) 115 printf(" %d",q1.data[i]); 116 if(s.top>0) //如果桌上有牌則依次輸出桌上的牌 117 { 118 printf("\n桌上的牌是"); 119 for(i=1;i<=s.top;i++) 120 printf(" %d",s.data[i]); 121 printf("\n"); 122 } 123 else 124 printf("\n桌上已經沒有牌了"); 125 } 126 else 127 { 128 printf("小哈獲勝\n"); 129 printf("小哈當前手中的牌是"); 130 for(i=q2.head;i<=q2.tail-1;i++) 131 printf(" %d",q2.data[i]); 132 if(s.top>0) //如果桌上有牌則依次輸出桌上的牌 133 { 134 printf("\n桌上的牌是"); 135 for(i=1;i<=s.top;i++) 136 printf(" %d",s.data[i]); 137 printf("\n"); 138 } 139 else 140 printf("\n桌上已經沒有牌了\n"); 141 } 142 return 0; 143 }
為了程序的魯棒性,需要進一步的測試,優化,暫時先不完善了(提示:需要設置一定的條件)