POJ 1753 Flip Game (递归枚举)
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 }
---
可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明
可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明