# 费解的开关(二进制+递推+思维)

费解的开关(二进制+递推+思维)


  • 题意:5*5的灯阵,每次按一盏灯的开关,并且这盏灯的上下左右也受到相同的影响(0->1,1->0),求使给定灯阵全1的最少步数。
  • 题解:
    • 每盏灯最多点击一次,点击两次相当于没有点击。
    • 最重要的性质:如果我们确定了第1行的灯的情况的话,那么后面的行数都可以依此递推,当前行灭的灯只能由下一行同一列的灯使之点亮。
  • 附上一个写的较好的题解
举个例子
11011
10110
01111
11111
第一行中第三盏灯为0,那么必须通过第二行的第3张灯将其点亮,当前行的灯只能由下一行的灯点亮,这样才不会影响当前行其他灯的情况。所以只需要确定第一行的灯的情况即可,第一行的灯控制第二行灯的点击情况,通过第二行灯将第一行灭的灯点亮后, 第二行灯处于灭状态的灯由第三行点亮,依次类推
  • Code:
//模块化编程思想

#include <bits/stdc++.h>
using namespace std;

#define mem(a) memset((a),0,sizeof(a))
#define fo(i,a,b) for(int (i)=(a);(i)<(b);(i)++)
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)//宏定义,编译时展开,占用编译时间
#define sf(x) scanf("%d",&(x))
const int inf=(0x7f7f7f7f);
const int maxn=3000;

int n;
int mp[5][5];
int dx[]={0,-1,0,1,0};
int dy[]={0,0,1,0,-1};

void turn(int x,int y){
    fo(i,0,5){
        int xx=x+dx[i];
        int yy=y+dy[i];
        if(xx>=0&&xx<5&&yy>=0&&yy<5){
            mp[xx][yy]^=1;
        }
    }
}

char mmp[5][5];
int work(){
    int ans=(1<<30);
    int cnt=0;

    //fo(i)循环枚举第一行灯的所有可能的点击情况,10010(表示点击第一盏灯和第四盏灯)
    fo(i,0,31){
        //初始化,
        fo(x,0,5)fo(y,0,5)mp[x][y]=mmp[x][y]-'0';
        cnt=0;

        //通过二进制数解码出灯的点击情况
        fo(j,0,5)
            if((i>>j)&1){
                cnt++;
                turn(0,j);
            }

        //依次处理前4行灯
        fo(j,0,4){
            fo(k,0,5){
                if(mp[j][k]==0){
                    turn(j+1,k);//通过下一行的灯使其点亮
                    cnt++;
                }
            }
        }

        //检查第五行灯是否是全亮的情况,如果不是由于前4行是全1的情况
        //第五行灭的灯无法点亮,故当前方案不合理
        bool is_ok=1;
        fo(j,0,5)if(mp[4][j]==0){
            is_ok=0;
            break;
        }

        if(is_ok)
        ans=min(ans,cnt);

    }

    if(ans>6)return -1;
    return ans;
}

int main(){
    sf(n);
    while(n--){
        fo(i,0,5)scanf("%s",mmp[i]);

        //fo(i,0,5)fo(j,0,5)cout<<mmp[i][j];

        cout<<work()<<endl;
    }

    return 0;
}

原文地址:https://www.cnblogs.com/sstealer/p/11123666.html

时间: 2024-10-14 11:48:33

# 费解的开关(二进制+递推+思维)的相关文章

Benelux Algorithm Programming Contest 2014 Final ACM-ICPC Asia Training League 暑假第一阶段第二场 E. Excellent Engineers-单点更新、区间最值-线段树 G. Growling Gears I. Interesting Integers-类似斐波那契数列-递推思维题

先写这几道题,比赛的时候有事就只签了个到. E. Excellent Engineers 传送门: 这个题的意思就是如果一个人的r1,r2,r3中的某一个比已存在的人中的小,就把这个人添加到名单中. 因为是3个变量,所以按其中一个变量进行sort排序,然后,剩下的两个变量,一个当位置pos,一个当值val,通过线段树的单点更新和区间最值操作,就可以把名单确定. 代码: 1 //E-线段树 2 #include<iostream> 3 #include<cstdio> 4 #incl

HDU 6092 Rikka with Subset 思维 递推

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6092 题目描述: 给你一个集合的所有子集各个和, 让你找到这个集合, 输出字典序最小 解题思路: 下标0上的数字肯定是1, 所以从下标为1的开始向后, 第一个不为零的数的下标肯定是集合中的一个数而且是最小的数......同时将这个数减减, 记住这个下标为cur(所以这个集合应该是唯一的?我没严格证明, 但是每一步取得值肯定都是唯一的啊, 而且从小到大)这样我们向后面偏移cur个单位, 如果两个数都

递推与递归专题练习

CH0301 递归实现指数型枚举 搜索与回溯,指数级算法. #include<bits/stdc++.h> #define rg register #define il inline #define co const template<class T>il T read(){ rg T data=0,w=1; rg char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') w=-1; ch=getchar(); } while(isdi

AcWing 95 费解的开关

目录 前言 题目链接 思路 代码 前言 博客咕咕咕了好久了,是时候写一下了 题目链接 AcWing 95 费解的开关 思路 首先可以看出 1.每一个位置顶多只会操作一次.因为如果操作两次的话,相当于不操作,必然是不满足最优解 2.在一套方案中,操作的顺序无关紧要. 3.如果我们确定了第I行的操作方案的话,那么后面的行数都可以依此递推,下面给出一个详细的解答. 11011 10110 01111 11111 比如说这个例子,如果我们确定了第1行,那么第二行所有的0(坐标:a[i][j]) 都只能是

【DP】一道递推题。。。

Bob想要构造一张由n个节点构成的图.构造的过程由两步组成:首先Bob会取出n个孤立的点,并把它们从1到n编号,然后对每个节点用一种颜色染色,Bob一共可以使用K种不同的颜色.接下来Bob会在这张图中加入一些有向边,对于每一个编号范围在[2,n]的节点i,Bob有可能选择一个节点j满足j < i并且节点i与j的颜色不同,然后加入一条从i到j的有向边,对于节点i,Bob也有可能不加任何的有向边.现在你需要回答Bob有可能构造出多少种不同的图. 输入: 第一行包含三个整数n,K. 输出: 输出一个整

递推和递归

一.递推算法基本思想: 递推算法是一种理性思维模式的代表,其根据已有的数据和关系,逐步推导而得到结果.递推算法的执行过程如下: 1)根据已有的·结果和关系,求解中间结果 2)判定是否达到要求,如果没有达到,则继续根据已知结果和关系求解中间结果:如果满足要求,则表示寻找到一个正确的答案. 递推算法往往需要用户知道答案和问题之间的逻辑关系.在许多数学问题中,都有着明确的计算公式可以遵循,因此往往可以采用递推来实现. 2.递推算法示例 如果一对两个月大的兔子以后每个月可以生一对兔子,而一对新生的兔子出

斐波那契 递推算法

/***Date : 2014.12.10***/ //递推算法:是理性思维模式的代表,根据已有的数据和关系,逐步推导而得出结果. //执行过程:1)根据已知的结果和关系,求解中间结果. ///////////////////// 2)判断是否满足要求,若未满足,则继续根据已知结果和关系求解中间结果:若满足要求,则表示寻找到一个正确答案. //13世纪,意大利数学家斐波那契的<算盘书>中记载:兔子产仔问题. //一对两个月大的兔子,每月都可产仔一对,小兔子两月后的每月也可产仔一对;即1月生,3

hihoCoder 1143 : 骨牌覆盖问题&#183;一(递推,矩阵快速幂)

[题目链接]:click here~~ 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 骨牌,一种古老的玩具.今天我们要研究的是骨牌的覆盖问题: 我们有一个2xN的长条形棋盘,然后用1x2的骨牌去覆盖整个棋盘.对于这个棋盘,一共有多少种不同的覆盖方法呢? 举个例子,对于长度为1到3的棋盘,我们有下面几种覆盖方式: 提示:骨牌覆盖 提示:如何快速计算结果 输入 第1行:1个整数N.表示棋盘长度.1≤N≤100,000,000 输出 第1行:1个整数,表示覆盖方案数 M

算法入门——递推

主要思想: 通过已知的条件(已知结果),利用特定的关系,逐步递推(顺推/逆推),直到有解或者无解. 主要分为两种:顺推,从已知条件出发,直至推出解. 逆推,从已知结果出发,直至推出解. 需要注意的:每一递推结果,都是下一步递推的条件. 顺推: 斐波那契数列  F0=0,F1=1,Fn=F(n-1)+F(n-2)(n>=2,n∈N*) 实例 兔子的总数有多少? 一对兔子,每月能生一对,而每对兔子3个月后可以生育.求12个月后共有多少兔子. #include<stdio.h> #define