POJ 1753,題目鏈接http://poj.org/problem?id=1753,翻譯一下整個題目的大概意思:
有4*4的正方形,每個格子要么是黑色,要么是白色,當把一個格子的顏色改變(黑->白或者白->黑)時,其周圍上下左右(如果存在的話)的格子的顏色也被反轉,問至少反轉幾個格子可以使4*4的正方形變為純白或者純黑?
主要思路如下:
1.對於每個格子,它要么反轉0次,要么反轉1次(當然,它的鄰格子也跟着反轉),因為它反轉偶數次和反轉0次的效果是一樣的,同理反轉奇數次的效果和反轉1次的效果是一樣的。
2.由於只有16個格子,我們可以選擇0個格子,1個格子,2個格子,3個格子......進行反轉,總的選擇情況為
3.當0個格子被反轉時,看它是否為純色,否則選擇一個格子進行反轉(有16種選擇),看反轉后是否為純色,否則選擇兩個格子進行反轉(有120種選擇),看反轉后是否為純色......
4.只要"3過程"中有純色出現,就停止"3過程",輸出相應的被選擇的格子個數,結束。如果16個格子都被翻轉了,還是沒變成純色,則輸出“Impossible”。
對於從16個格子中選取n個格子的所有組合,請看前一篇文章從數組中取出n個元素的所有組合(遞歸實現),這里不再敘述。
整個程序代碼如下:
1 /* 2 POJ 1753 Flip Game (遞歸枚舉) 3 By Microgoogle 4 */ 5 #include <stdio.h> 6 #include <stdlib.h> 7 8 //所有都是白的,或者所有都是黑的 9 int all_white_or_black(int* bits, int len) 10 { 11 int i = 0; 12 for (i = 0; i < len - 1; i++) 13 if (bits[i] != bits[i + 1]) 14 return 0; 15 return 1; 16 } 17 18 //改變一個格子的顏色,並根據其所在位置改變其周圍格子的顏色 19 void change_color(int* arr, int i) 20 { 21 arr[i] = !(arr[i]); 22 int x = i/4; 23 int y = i%4; 24 if (y < 3) 25 arr[i + 1] = !(arr[i + 1]); 26 if (y > 0) 27 arr[i - 1] = !(arr[i - 1]); 28 if (x > 0) 29 arr[i - 4] = !(arr[i - 4]); 30 if (x < 3) 31 arr[i + 4] = !(arr[i + 4]); 32 } 33 34 //遞歸判斷 35 //這個完全用了前一篇文章的遞歸方法,只是在else語句中添加了整個圖形是否為純色的判斷而已 36 void combine(int* arr, int len, int* result, int count, const int NUM, int* last) 37 { 38 int i; 39 for (i = len; i >= count; i--) 40 { 41 result[count - 1] = i - 1; 42 if (count > 1) 43 combine(arr, i - 1, result, count - 1, NUM, last); 44 else 45 { 46 int j = 0; 47 //在這里生成arr的副本 48 int* new_arr = (int*)malloc(sizeof(int)*16); 49 for (j = 0; j < 16; j++) 50 new_arr[j] = arr[j]; 51 52 for (j = NUM - 1; j >=0; j--) 53 { 54 change_color(new_arr, result[j]); 55 } 56 if (all_white_or_black(new_arr, 16)) 57 { 58 *last = NUM; 59 free(new_arr); 60 break; 61 } 62 free(new_arr); 63 } 64 } 65 } 66 67 int main() 68 { 69 char str[5]; 70 int bits[16]; 71 int count = 15; 72 int lines = 4; 73 while (lines--) 74 { 75 scanf("%s", str); 76 int i; 77 for (i = 0; i < 4; i++) 78 { 79 if (str[i] == 'b') 80 bits[count--] = 1; 81 else 82 bits[count--] = 0; 83 } 84 } 85 86 if (all_white_or_black(bits, 16)) 87 printf("%d\n", 0); 88 else 89 { 90 //生成bits數組的副本 91 int* new_bits = (int*)malloc(sizeof(int)*16); 92 int i; 93 for (i = 0; i < 16; i++) 94 new_bits[i] = bits[i]; 95 96 int j; 97 //這里last用來接受combine函數里面的NUM,即需要的步數 98 int last = 0; 99 for (j = 1; j <= 16; j++) 100 { 101 int* result = (int*)malloc(sizeof(int)*j); 102 combine(new_bits, 16, result, j, j, &last); 103 if (last == j) 104 { 105 printf("%d\n", last); 106 break; 107 } 108 //new_bits已被改變,所以要還原為bits 109 for (i = 0; i < 16; i++) 110 new_bits[i] = bits[i]; 111 112 free(result); 113 } 114 free(new_bits); 115 116 if (j == 17) 117 printf("Impossible\n"); 118 } 119 120 return 0; 121 }