朝题夕解之以递推为背景的开关问题(一)

简介: 朝题夕解之以递推为背景的开关问题(一)

题目描述

微信图片_20221018151841.jpg解题报告


一、题意理解

游戏者改变一个灯的状态会产生连锁反应:和这个灯上下左右相邻的灯也要相应地改变其状态。

使用windows自带的画图,摁住shift拖动鼠标画出下列的图形进行演示。

微信图片_20221018151936.png

样例演示:

微信图片_20221018152001.png

二、每一行开关的操作完全由前一行灯的亮灭决定


  1. 假设第一行的所有状态用枚举来确定,每个开关要么摁,要么不摁,在这里就是2 5 2^52 5 次种选法。
  2. 依次依据前一行的亮灭状态,决定它的下一行可以怎么摁,才能保证这个前一行是亮的。


/

微信图片_20221018152046.jpg

三、细节敲定


1.如何枚举第一行的32中操作。一个五位二进制正好可以表示这32种操作。比如

11010 => 对应第26个操作。那么0 ~ 2 5 2^52 5-1就可以逐一对应枚举第一行会有的32种方案


2.开关点亮函数

点击一个位置的开关以后,它上下左右四个位置的开关都会被改变状态。用四个i f ifif就显得太麻烦了。这里考虑的是通过添加偏移量实现。

微信图片_20221018152250.jpg

3.时间复杂度

32 ∗ 25 ∗ 5 ∗ 500 = 2000000 32 * 25 * 5 * 500 = 200000032∗25∗5∗500=2000000,大概是两百万次的运算。是完全没有问题的


参考代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 6;
char g[N][N],backup[N][N];
int dx[] = {-1,0,1,0,0} , dy[] = {0,-1,0,1,0};
//补全turn 函数
void turn(int x,int y)
{
    for(int i = 0; i < 5;i++)
    {
        int a = x+dx[i] , b = y + dy[i];
        //判断边界
        if(a < 0 || a >= 5 || b < 0 || b>= 5) continue;
        //更新状态
        g[a][b] ^= 1;
    }
}
int main()
{
    int T;
    cin >> T;
    while(T--)
    {
        //构建地图
        for(int i = 0; i < 5;i++) cin >> g[i];
        int res = 10;//记录答案
        //枚举第一行的32种选择
        for(int op = 0; op < 32;op++)
        {
            memcpy(backup,g,sizeof g);
            int step = 0;//记录执行的步骤
            //处理当前这个方案是否有可以摁亮的灯
            for(int i = 0; i < 5; i++)
            {
                if(!(op >> i &1))
                {
                    step ++;
                    turn(0,i);
                }
            }
            //根据第一行现在的情况,处理后面四行的处理情况
            for(int i = 0; i < 4;i++)
            {
                for(int j = 0; j < 5;j++)
                if(g[i][j] == '0') 
                {
                    step ++;
                    turn(i+1,j);
                }
            }
            //遍历最后一行,倘若有黑的灯,那么当前方案失败
             bool dark = false;//标记
            for(int i = 0; i < 5;i++)
                if(g[4][i] == '0')
                {
                    dark = true;
                    break;
                }
            if(!dark) res = min(res,step);
            memcpy(g,backup,sizeof g);//从备份中把数据拿回来
        }
            if(res > 6) res = -1;//res = -1代表无解
            cout << res << endl;
    }
    return 0;
}


相关文章
|
8月前
【每日一题Day146】给定行和列的和求可行矩阵 | 贪心
【每日一题Day146】给定行和列的和求可行矩阵 | 贪心
59 0
|
5月前
|
前端开发
背景滑动,动感加倍:CSS动画对角线效果全解析!
背景滑动,动感加倍:CSS动画对角线效果全解析!
|
7月前
|
Java
三阶魔方公式详解及快速解法方法介绍
三阶魔方公式详解及快速解法方法介绍
|
7月前
|
算法 C++ 容器
心得经验总结:排列组合问题之圆形分布
心得经验总结:排列组合问题之圆形分布
51 0
|
8月前
|
测试技术
【深度优先搜索】【组合数学】【动态规划】1467.两个盒子中球的颜色数相同的概率
【深度优先搜索】【组合数学】【动态规划】1467.两个盒子中球的颜色数相同的概率
【最优方案】合唱队形
【最优方案】合唱队形
206 0
|
存储 算法 C语言
深度理解递归,手撕经典递归问题(汉诺塔,青蛙跳台阶),保姆级教学。
深度理解递归,手撕经典递归问题(汉诺塔,青蛙跳台阶),保姆级教学。
|
算法
斜方向三消查找算法的原理和实现
昨天的文章中我们讲了三消查找算法的原理和实现,在宝石方块中,除了水平和竖直的三消之外,斜方向上也可以三消,今天这篇就讲一下斜方向上三消的原理和实现
135 0
斜方向三消查找算法的原理和实现
动态规划爬楼梯(为什么到i级的方法=i-1级的方法+到i-2级的方法)
想一想你现在就站在第i-1级台阶上,到达这第i-1级的台阶有100种方法,每一种方法都走到这里(第i-1级台阶),这100种方法中每一种方法都差一步就到第i级台阶了。
66 0
动态规划爬楼梯(为什么到i级的方法=i-1级的方法+到i-2级的方法)
LeetCode每日一题(10)——三维形体投影面积(保姆级)
三维形体投影面积 1.题目 2.示例 3.思路 理解题目 解题思路 4.代码
134 0
LeetCode每日一题(10)——三维形体投影面积(保姆级)