• POJ 3185 The Water Bowls 反转+点灯游戏


    一、题目大意

    有20盏灯(其实20盏灯数据量太少了,1e7我觉得差不多都可以过)放在同一行,点亮某一盏灯,它左右两边的灯也会亮,然后边缘特殊考虑,电亮两端的灯,只会照亮它相邻的那一个。

    二、解题思路

    这其实就是一个反转问题,我们从第二盏灯开始循环到第20盏灯,对于每一次循环的i,我们计算出i-1的灯是否亮着,如果i-1亮着,我们就continue,如果i-1不亮,那么电亮i,来照亮i-1。

    然后计算每盏灯是不是亮着,可以记录一个数组f[i],记录是否有 [i-1,i+1]的区间内被点亮,假如说一个位置i,f[i]==1,f[i-1]==1,那么相当于i位置与起始时的i位置情况相同,如果f[i]和f[i-1]中有一个为0,另一个为1的话,那么相当于i位置与起始时的情况相反。

    这样我们用尺取法,每次维护i-1和i-2位置的f[i]的和,这样结合i位置的起始情况,就知道i位置是不是亮着的,然后生成f[i]的值,不断循环即可,循环结束之后,判断下最后一盏灯是不是亮着的,如果是的话,这是一个可行解,然后把f[i]数组求和,就是反转总次数。

    因为我们是从第二盏灯开始考虑的,所以我们要循环判断下第一盏灯f[1]为1或0的两种情况,分别求解。

    这种反转问题(点灯游戏),特点就是反转两次和没反转一样,然后都是牵一发而动全身,这种问题解题的关键就是找到可以唯一决定某个位置的条件,例如当f[i],f[i-1]为定值时,f[i+1]的值可以直接决定i是不是亮着的,这样的话,每次通过i+1保证i,然后不断循环,最后对无法保证的区间([20,20])做判断,通过判断保存可行解,不通过则找下一种情况。

    三、代码

    1. #include
    2. using namespace std;
    3. int revCnt[27], ansCnt = 0x3f3f3f3f;
    4. bool drinkable[27];
    5. void input()
    6. {
    7. int x;
    8. for (int i = 1; i <= 20; i++)
    9. {
    10. scanf("%d", &x);
    11. if (x == 0)
    12. {
    13. drinkable[i] = true;
    14. }
    15. else
    16. {
    17. drinkable[i] = false;
    18. }
    19. }
    20. }
    21. void flushRevCnt()
    22. {
    23. for (int i = 1; i <= 20; i++)
    24. {
    25. revCnt[i] = 0;
    26. }
    27. }
    28. void saveAns()
    29. {
    30. int currentAns = 0;
    31. for (int i = 1; i <= 20; i++)
    32. {
    33. currentAns += revCnt[i];
    34. }
    35. if (currentAns < ansCnt)
    36. {
    37. ansCnt = currentAns;
    38. }
    39. }
    40. void solve()
    41. {
    42. int currentSum = revCnt[1];
    43. for (int i = 2; i <= 20; i++)
    44. {
    45. bool isDrinkable = drinkable[i - 1];
    46. if (currentSum % 2 != 0)
    47. {
    48. isDrinkable = !drinkable[i - 1];
    49. }
    50. if (!isDrinkable)
    51. {
    52. revCnt[i] = 1;
    53. }
    54. currentSum += revCnt[i];
    55. // 我们这个位置i,作为下次的判断条件,那么i-1,i,i+1可以作为比较的因素,i-1-1得去掉
    56. if (i - 1 - 1 >= 1)
    57. {
    58. currentSum -= revCnt[i - 1 - 1];
    59. }
    60. }
    61. int lastRevCnt = revCnt[19] + revCnt[20];
    62. bool isLastDrinkable = drinkable[20];
    63. if (lastRevCnt % 2 != 0)
    64. {
    65. isLastDrinkable = !drinkable[20];
    66. }
    67. if (isLastDrinkable)
    68. {
    69. saveAns();
    70. }
    71. }
    72. int main()
    73. {
    74. input();
    75. flushRevCnt();
    76. solve();
    77. flushRevCnt();
    78. revCnt[1] = 1;
    79. solve();
    80. printf("%d\n", ansCnt);
    81. return 0;
    82. }

  • 相关阅读:
    IO模型简介
    NoSQL之Redis配置与优化
    基于JAVA球迷信息交流论坛计算机毕业设计源码+数据库+lw文档+系统+部署
    2022年TypeScript 最细项目实践:四步走高效改造现有的 JavaScript 项目实战
    vscode上搭建go开发环境
    单页面应用(SPA)与多页面应用(MPA)的区别及优缺点
    浅拷贝、深拷贝与序列化【初级Java必需理解的概念】
    vue大型电商项目尚品汇(前台篇)day05终结篇
    vue2 与vue3的差异汇总
    024 - STM32学习笔记 - 液晶屏控制(一) - LTDC与DMA2D初始
  • 原文地址:https://blog.csdn.net/qq_53038151/article/details/132842145