• 《算法竞赛进阶指南》 第一章 Acwing 95. 费解的开关


    地址 https://www.acwing.com/problem/content/97/

    你玩过“拉灯”游戏吗?
    25 盏灯排成一个 5×5 的方形。
    每一个灯都有一个开关,游戏者可以改变它的状态。
    每一步,游戏者可以改变某一个灯的状态。
    游戏者改变一个灯的状态会产生连锁反应:和这个灯上下左右相邻的灯也要相应地改变其状态。
    我们用数字 1 表示一盏开着的灯,用数字 0 表示关着的灯。
    下面这种状态
    
    10111
    01101
    10111
    10000
    11011
    
    在改变了最左上角的灯的状态后将变成:
    01111
    11101
    10111
    10000
    11011
    
    再改变它正中间的灯后状态将变成:
    01111
    11001
    11001
    10100
    11011
    
    给定一些游戏的初始状态,编写程序判断游戏者是否可能在 6 步以内使所有的灯都变亮。
    
    输入格式
    第一行输入正整数 n,代表数据中共有 n 个待解决的游戏初始状态。
    以下若干行数据分为 n 组,每组数据有 5 行,每行 5 个字符。
    每组数据描述了一个游戏的初始状态。
    各组数据间用一个空行分隔。
    
    输出格式
    一共输出 n 行数据,每行有一个小于等于 6 的整数,它表示对于输入数据中对应的游戏状态最少需要几步才能使所有灯变亮。
    对于某一个游戏初始状态,若 6 步以内无法使所有灯变亮,则输出 −1。
    
    数据范围
    0<n≤500
    输入样例:
    
    3
    00111
    01011
    10001
    11010
    11100
    
    11101
    11101
    11110
    11111
    11111
    
    01111
    11111
    11111
    11111
    11111
    
    输出样例:
    3
    2
    -1
    

    解答
    由游戏规则可知 每点可以至多一次(点击两次恢复原状) 点击ABC CBA BAC等操作次序不影响最后达到的状态
    思路如下 第一行有5个点 每个点的状态非0即1 那么就是2^5个状态集合
    以这些第一行的状态为起点 逐步递推出下一行如何操作

    如图 第一行状态确定后 无论第二行状态如何 我们必须点击第二行蓝色点才能使得第一行全部为1
    而想使得第二行完全为1 则需要点击第三行 如果递推
    最后推断到最后一行 可知是否有解。

    #include <iostream>
    #include <string>
    #include <algorithm>
    
    using namespace std;
    
    
    int n;
    int ans;
    string gra[5];
    
    int addx[5] = { 1,-1,0,0,0 };
    int addy[5] = { 0,0,0,-1,1 };
    
    
    void click(int g[5][5], int x, int y) {
    	for (int i = 0; i < 5; i++) {
    		int newx = x + addx[i];
    		int newy = y + addy[i];
    
    		if (newx >= 0 && newx < 5 && newy >= 0 && newy < 5) {
    			g[newx][newy] ^= 1;
    		}
    	}
    }
    
    
    void solve()
    {
    	ans = -1;
    	for (int i = 0; i < 1 << 5; i++) {
    		int currClick = 0;
    		int tmp[5][5];
    		for (int i = 0; i < 5; i++) {
    			for (int j = 0; j < 5; j++) {
    				tmp[i][j] = gra[i][j] - '0';
    			}
    		}
    
    		for (int k = 0; k < 5; k++) {
    			if (i & (1 << k)) {
    				click(tmp, 0, k);
    				currClick++;
    			}
    		}
    
    		//第一排确认以后 递推后面的点击位置
    		for (int k = 0; k < 4; k++) {
    			for (int j = 0; j < 5; j++) {
    				if (tmp[k][j] != 1) {click(tmp, k + 1, j); currClick++;}
    			}
    		}
    
    		if (currClick > 6) continue;
    
    		//检查最后一排是否为全1
    		for (int i = 0; i < 5; i++) {
    			if (tmp[4][i] == 0) { currClick = -1; break; }
    		}
    
    		if (currClick != -1 && (-1 == ans || currClick < ans)) {ans = currClick;}
    	}
    }
    
    
    int main() {
    	cin >> n;
    
    	while (n--) {
    		for (int i = 0; i < 5; i++) {
    			cin >> gra[i];
    		}
    		solve();
    		cout << ans << endl;
    	}
    
    	return 0;
    }
    

    我的视频题解空间

    作 者: itdef
    欢迎转帖 请保持文本完整并注明出处
    技术博客 http://www.cnblogs.com/itdef/
    B站算法视频题解
    https://space.bilibili.com/18508846
    qq 151435887
    gitee https://gitee.com/def/
    欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
    如果觉得不错,欢迎点赞,你的鼓励就是我的动力
    阿里打赏 微信打赏
  • 相关阅读:
    call/cc 总结 | Scheme
    用call/cc合成所有的控制流结构
    词法作用域 vs 动态作用域
    数论部分第二节:埃拉托斯特尼筛法
    1022: [SHOI2008]小约翰的游戏John【Nim博弈,新生必做的水题】
    C++面向对象作业1
    数论部分第一节:素数与素性测试【详解】
    基数排序与桶排序,计数排序【详解】
    计蒜客:百度的科学计算器(简单)【python神解】
    优质免费在线学习网站【自用】
  • 原文地址:https://www.cnblogs.com/itdef/p/14631767.html
Copyright © 2020-2023  润新知