• POJ 3279 Fliptile 反转 + 点灯游戏


    一、题目大意

    本题目其实是关于一个点灯游戏的玩法,相信很多人多玩过这个游戏,每次电亮一盏灯,这盏灯周围的4个灯也都会一起点亮,本题目是要求出最少的操作次数,电亮所有的灯,并把电亮的灯输出在答案里。

    二、解题思路

    我们能够直到,同样一盏灯电亮两次,等于没点!所以我们记录一个数组f[i][j],用来放置每个坐标是否被电亮过。

    然后我们只需要计算f[i][j]+f[i-1][j]+f[i+1][j]+f[i][j-1]+f[i][j+1]的和sum,如果sum是奇数,那么该位置与最开始输入的位置的颜色相反,否则颜色相同。

    那么这就变成了一个反转问题,我们利用二进制,从0000,到1111(N=4时)枚举第一行的所有点灯情况,然后从第2行开始到M行循环所有坐标,判断如果它上一行灯是灭着的,就电亮这盏灯,否则就continue

    然后到最后一行判断下,如果最后一行有灯是灭着的,那么这个情况无解(因为最后一行再改动一定会影响到上面的,那么其实不可能全亮了),遍历第一行的下一种情况,如果最后一行所有灯全亮,那么把当前f[i][j]数组求和,如果小于记录的ans,那么就保存下当前的结果。

    最后判断下,如果ans从未被修改,那么输出IMPOSSIBLE,否则输出记录的结果

    复杂性是 (2^N)*(MN),是可行的。

    三、代码

    1. #include
    2. using namespace std;
    3. int towPow[27], revCnt[17][17], M, N, ansRevCnt, count, ans[17][17];
    4. bool white[17][17];
    5. void initTwoPow()
    6. {
    7. towPow[0] = 1;
    8. for (int i = 1; i <= 20; i++)
    9. {
    10. towPow[i] = towPow[i - 1] * 2;
    11. }
    12. }
    13. void input()
    14. {
    15. scanf("%d%d", &M, &N);
    16. int x;
    17. for (int i = 1; i <= M; i++)
    18. {
    19. for (int j = 1; j <= N; j++)
    20. {
    21. scanf("%d", &x);
    22. if (x == 0)
    23. {
    24. white[i][j] = true;
    25. }
    26. else
    27. {
    28. white[i][j] = false;
    29. }
    30. }
    31. }
    32. ansRevCnt = 0x3f3f3f3f;
    33. }
    34. void flushRevCnt()
    35. {
    36. for (int i = 1; i <= M; i++)
    37. {
    38. for (int j = 1; j <= N; j++)
    39. {
    40. revCnt[i][j] = 0;
    41. }
    42. }
    43. }
    44. // 计算i,j坐标的一圈五个位置的结果
    45. int calcRevCntAroundIJ(int i, int j)
    46. {
    47. int result = revCnt[i][j];
    48. if (i > 1)
    49. {
    50. result += revCnt[i - 1][j];
    51. }
    52. if (j > 1)
    53. {
    54. result += revCnt[i][j - 1];
    55. }
    56. if (j < N)
    57. {
    58. result += revCnt[i][j + 1];
    59. }
    60. if (i < M)
    61. {
    62. result += revCnt[i + 1][j];
    63. }
    64. return result;
    65. }
    66. // 判断最后一行是否全是白色
    67. bool judgeLastLine()
    68. {
    69. for (int col = 1; col <= N; col++)
    70. {
    71. int currentRevCnt = calcRevCntAroundIJ(M, col);
    72. bool isWhite = white[M][col];
    73. if (currentRevCnt % 2 != 0)
    74. {
    75. isWhite = !white[M][col];
    76. }
    77. if (!isWhite)
    78. {
    79. return false;
    80. }
    81. }
    82. return true;
    83. }
    84. void saveAns()
    85. {
    86. int currentRevCnt = 0;
    87. for (int i = 1; i <= M; i++)
    88. {
    89. for (int j = 1; j <= N; j++)
    90. {
    91. currentRevCnt += revCnt[i][j];
    92. }
    93. }
    94. if (currentRevCnt >= ansRevCnt)
    95. {
    96. return;
    97. }
    98. ansRevCnt = currentRevCnt;
    99. for (int i = 1; i <= M; i++)
    100. {
    101. for (int j = 1; j <= N; j++)
    102. {
    103. ans[i][j] = revCnt[i][j];
    104. }
    105. }
    106. }
    107. void solve()
    108. {
    109. for (int i = 2; i <= M; i++)
    110. {
    111. for (int j = 1; j <= N; j++)
    112. {
    113. int beforeLineRevCnt = calcRevCntAroundIJ(i - 1, j);
    114. bool beforeLineIsWhite = white[i - 1][j];
    115. if (beforeLineRevCnt % 2 != 0)
    116. {
    117. beforeLineIsWhite = !white[i - 1][j];
    118. }
    119. if (!beforeLineIsWhite)
    120. {
    121. revCnt[i][j] = 1;
    122. }
    123. }
    124. }
    125. if (judgeLastLine())
    126. {
    127. saveAns();
    128. }
    129. }
    130. // 利用二进制,来枚举第一行翻与不翻的所有可能
    131. void handleFirstLineByBin(int numBin)
    132. {
    133. for (int j = N - 1; j >= 0; j--)
    134. {
    135. int x = numBin & towPow[j];
    136. x = x >> j;
    137. if (x == 1)
    138. {
    139. revCnt[1][N - j] = 1;
    140. }
    141. else
    142. {
    143. revCnt[1][N - j] = 0;
    144. }
    145. }
    146. }
    147. void outputAns()
    148. {
    149. if (ansRevCnt == 0x3f3f3f3f)
    150. {
    151. printf("IMPOSSIBLE\n");
    152. return;
    153. }
    154. for (int i = 1; i <= M; i++)
    155. {
    156. for (int j = 1; j <= N; j++)
    157. {
    158. if (j != N)
    159. {
    160. printf("%d ", ans[i][j]);
    161. }
    162. else
    163. {
    164. printf("%d\n", ans[i][j]);
    165. }
    166. }
    167. }
    168. }
    169. int main()
    170. {
    171. initTwoPow();
    172. input();
    173. int base = 1048576, len = towPow[N];
    174. for (int i = 0; i < len; i++)
    175. {
    176. flushRevCnt();
    177. int numBin = base + i;
    178. handleFirstLineByBin(numBin);
    179. solve();
    180. }
    181. outputAns();
    182. return 0;
    183. }

  • 相关阅读:
    小米、华为、iPhone、OPPO、vivo如何在手机让几张图拼成一张?
    [附源码]计算机毕业设计JAVA企业公开招聘系统
    基于PPT的三维光路结构示意图绘制实例演示
    CSS BFC介绍
    平均回复在5s内的快捷短语
    计算机组成原理之计算机系统概论、计算机的发展史、系统总线,三章开篇讲
    软考中级怎么入户深圳,需要什么条件?
    GBase 8c V3.0.0数据类型——条件表达式函数
    脑机接口的发展研究
    The widget on which setState() or markNeedsBuild() was called exception
  • 原文地址:https://blog.csdn.net/qq_53038151/article/details/132823227