Openjudge 2811 熄灯问题 枚举 爆搜

缺乏、安全感 2022-06-17 12:21 204阅读 0赞

熄灯问题链接如下 http://bailian.openjudge.cn/practice/2811/

该题尝试得到一组开关的状态使得灯全部被熄灭,经过分析容易得到,我们枚举第一行开关的状态后,为了达到目的,剩下所有行的开关的状态都是固定的且是由第一行开关的状态推导出来的,因为第一行开关状态固定后,可以影响第一行灯的状态的只有第二行开关的状态了,以此类推,到确定最后一行灯的状态后我们就可以验证最后得到的灯的状态是不是理想的状态了

本题有两个坑,一个是如何枚举第一行灯的状态,得到一个全排列,一种方法是最暴力的,多个for循环叠加,但是如果该行个数比较多的时候就不可行,另一种方法则是利用回溯(递归?)来生成第一行的状态,第二个坑则还是初始化的问题,切记,当我们处理完状况1,又处理状况2的时候,要把能想到的所有的初始化都做了,这里我一开始没有清空send数组导致一直出错。。。同样的错误不可以犯第三次了

代码如下

递归生成全排列版本:

  1. #include <memory.h>
  2. #include<stdio.h>
  3. #include<iostream>
  4. #include<math.h>
  5. using namespace std;
  6. int button[6] ;
  7. int send[10][10];
  8. int a[10][10];
  9. int b[10][10];
  10. int dx[5] = {0,0,1,-1,0};
  11. int dy[5] = {1,-1,0,0,0};
  12. bool done;
  13. bool check() //检查是否全熄灭
  14. {
  15. for (int i = 0; i < 5; i++)
  16. for (int j = 0; j < 6; j++)
  17. if (b[i][j] == 1) return false; //b[i][j]=1代表这个灯是点亮的
  18. return true;
  19. }
  20. void op(int x, int y) //根据开关进行操作
  21. {
  22. int x1, y1;
  23. for (int i = 0; i < 5; i++)
  24. {
  25. x1 = x + dx[i]; y1 = y + dy[i];
  26. if (x1 >= 0 && x1 < 5 && y1 >= 0 && y1 < 6) b[x1][y1] = !b[x1][y1];
  27. }
  28. }
  29. void work() //找到一组第一行的状态后,进行操作
  30. {
  31. memset(send, 0, sizeof(send)); //必须初始化send数组,否则之前开关的状态会影响到现在
  32. for (int i = 0; i < 5; i++)
  33. for (int j = 0; j < 6; j++)
  34. b[i][j] = a[i][j]; //初始化b数组使得其与a数组相同
  35. for (int i = 0; i < 6; i++)
  36. send[0][i] = button[i];
  37. for (int i = 0; i < 4; i++) //对除最后一行外的灯操作
  38. {
  39. for (int j = 0; j < 6; j++) //按照搜索出来的状态,熄灯操作
  40. if (send[i][j] == 1) op(i, j); //send[i][j]==1 代表这里要按下去,即改变状态
  41. for (int j = 0; j < 6; j++) //根据当前行灯的状态,决定下一行的操作
  42. if (b[i][j] == 1) send[i + 1][j] = 1;
  43. }
  44. for (int j = 0; j < 6; j++) if (send[4][j] == 1) op(4, j); //对最后一行进行操作
  45. if (check() == true)
  46. {
  47. done = true;
  48. }
  49. }
  50. void product_button(int x)
  51. {
  52. if (done) return;
  53. button[x] = 0;
  54. if (x+1<6) product_button(x + 1);
  55. else work(); //枚举出一种第一行开关状态,进行判断
  56. if (done) return;
  57. button[x] = 1;
  58. if (x+1<6) product_button(x + 1);
  59. else work(); //枚举出一种第一行开关状态,进行判断
  60. if (done) return;
  61. }
  62. void solve()
  63. {
  64. product_button(0);
  65. }
  66. int main()
  67. {
  68. for (int i = 0; i < 5; i++)
  69. for (int j = 0; j < 6; j++)
  70. cin >> a[i][j];
  71. done = false;
  72. solve();
  73. for (int i = 0; i < 5; i++)
  74. {
  75. for (int j = 0; j < 6; j++)
  76. if (j==0) cout << send[i][j];
  77. else cout << " " << send[i][j];
  78. cout << endl;
  79. }
  80. return 0;
  81. }

程设期末上机考试有一道类似的题,还没有做出来,明天想一想

题目链接:http://cxsjsx.openjudge.cn/final2015/J/

发表评论

表情:
评论列表 (有 0 条评论,204人围观)

还没有评论,来说两句吧...

相关阅读

    相关 【Java】问题解决

    今天早上客户来反映问题说首页上的一个卡片查询不了数据,代码比较旧了重新找回来发现还留下这样的一个坑。 枚举中是这样的: ![这里写图片描述][10dcc300e8b124e

    相关 假币问题

    2692:假币问题 描述 赛利有12枚银币。其中有11枚真币和1枚假币。假币看起来和真币没有区别,但是重量不同。但赛利不知道假币比真币轻还是重。于是他向朋友借了一架天平