题目描述

现有n盏灯,以及m个按钮。每个按钮可以同时控制这n盏灯——按下了第i个按钮,对于所有的灯都有一个效果。按下i按钮对于第j盏灯,是下面3中效果之一:如果a[i][j]为1,那么当这盏灯开了的时候,把它关上,否则不管;如果为-1的话,如果这盏灯是关的,那么把它打开,否则也不管;如果是0,无论这灯是否开,都不管。

现在这些灯都是开的,给出所有开关对所有灯的控制效果,求问最少要按几下按钮才能全部关掉。

输入格式:

前两行两个数,n m

接下来m行,每行n个数,a[i][j]表示第i个开关对第j个灯的效果。

输出格式:

一个整数,表示最少按按钮次数。如果没有任何办法使其全部关闭,输出-1

输入样例:

3

2

1 0 1

-1 1 0

输出样例#1:

2

说明

对于20%数据,输出无解可以得分。

对于20%数据,n<=5

对于20%数据,m<=20

上面的数据点可能会重叠。

对于100%数据 n<=10,m<=100


题目分析

关灯问题——状态压缩经典

所谓状态压缩

就是将问题可能遇到的每一个状态用一个唯一的二进制数表示

其复杂度一般都是指数级的

这也注定了状压类的题数据规模都不会太大

此题中我们以1表示开灯状态,0表示关灯状态

这样我们可以以一个长度为n的二进制数唯一的表示每个状态

接着就可以依靠既定的开关关系将每个状态连接起来

即将隐式图转化为显式图通过BFS最短路解决

以灯全开状态为起点

二进制为n个1 ,十进制表示为(1<< n)-1

开始枚举m个开关以得到接下来的m个状态

for(int i=1;i<=m;i++)
{
    ss=(1<< n)-1;
    for(int j=1;j<=n;j++)
    {
        if( a[i][j]==1 && (ss&(1<<j-1)) ) ss^=(1<<j-1);
        else if( a[i][j]==-1 && !(ss&(1<<j-1)) ) ss|=(1<<j-1);
    }
}

ss&(1<< j-1)此运算用以检查当前状态的第j位是否为1

1<< j-1意思是将1左移j-1位,移动后只有第j位上是1

若开关操作为1且当前状态第j位是1

ss^=(1<< j-1) 表示 1与1异或后得0

若开关操作为-1且当前状态第j位是0

ss|=(1 << j-1) 表示 1或0 后得1 (此处异或操作也对,因为1异或0得1

之后便用相同的方法在得到的每个状态上再不断搜索每个状态

由于是BFS,所以一旦某一步状态表示为0(十进制二进制的0写法都是0)

则当前步数必定是最短操作数

若遍历完所有状态都没有0,则输出-1

记得搜索过的状态要打vis标记避免重复访问


#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;

int read()
{
    int f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}

void print(int x)
{
    if(x<0){putchar('-');x=-x;}
    if(x>9)print(x/10);
    putchar(x%10+'0');
}

int n,m;
int a[110][1010];
struct node{int s,step;};//s存储状态,step存储当前步数
bool vis[1000010];

int spfa()
{
    int ss;
    queue<node> q;
    q.push( (node) {(1<<n)-1,0} );
    vis[(1<<n)-1]=true;//以全开为初始状态,二进制为n个1,十进制如代码

    while(!q.empty())
    {
        node u=q.front();
        q.pop();
        if(u.s==0){return u.step;}//若状态为0,则返回当前步数

        for(int i=1;i<=m;i++)
        {
            ss=u.s;
            for(int j=1;j<=n;j++)//由于开关对所有灯都影响,所以每个灯都遍历
            {
                if( a[i][j]==1 && (ss&(1<<j-1)) ) ss^=(1<<j-1);
                else if( a[i][j]==-1 && !(ss&(1<<j-1)) ) ss|=(1<<j-1);
            }//位运算解释如上文本

            if(!vis[ss])//若该状态未访问,就加入队列
            {
                q.push( (node) {ss,u.step+1} );
                vis[ss]=true;
            }
        }
    }
    return -1;
}

int main()
{
    n=read();m=read();
    for(int i=1;i<=m;i++)
    for(int j=1;j<=n;j++)
    a[i][j]=read();//保存每个开关操作对灯的影响

    print(spfa());
    return 0;
}

洛谷 P2622 关灯问题II【状压DP;隐式图搜索】的更多相关文章

  1. 洛谷 P2622 关灯问题II(状压DP入门题)

    传送门 https://www.cnblogs.com/violet-acmer/p/9852294.html 题解: 相关变量解释: int n,m; ];//a[i][j] : 第i个开关对第j个 ...

  2. 关灯问题II 状压DP

    关灯问题II 状压DP \(n\)个灯,\(m\)个按钮,每个按钮都会对每个灯有不同影响,问最少多少次使灯熄完. \(n\le 10,m\le 100\) 状压DP的好题,体现了状压的基本套路与二进制 ...

  3. 洛谷 P2622 关灯问题II【状压DP】

    传送门:https://www.luogu.org/problemnew/show/P2622 题面: 题目描述 现有n盏灯,以及m个按钮.每个按钮可以同时控制这n盏灯--按下了第i个按钮,对于所有的 ...

  4. 洛谷P2622 关灯问题II

    洛谷题目链接 声明: 本篇文章不讲基础,对萌新不太友好,(我就是萌新),要学状压$dp$的请另寻,这篇文章只是便于本人查看.... 首先看到$n<=10$,就可以考虑状压了,要求最小值,所以初始 ...

  5. 【题解】洛谷P3959 [NOIP2017TG] 宝藏(状压DP+DFS)

    洛谷P3959:https://www.luogu.org/problemnew/show/P3959 前言 NOIP2017时还很弱(现在也很弱 看出来是DP 但是并不会状压DP 现在看来思路并不复 ...

  6. 洛谷 P1278 单词游戏 【状压dp】

    题目描述 Io和Ao在玩一个单词游戏. 他们轮流说出一个仅包含元音字母的单词,并且后一个单词的第一个字母必须与前一个单词的最后一个字母一致. 游戏可以从任何一个单词开始. 任何单词禁止说两遍,游戏中只 ...

  7. 洛谷P2704 [NOI2001]炮兵阵地 [状压DP]

    题目传送门 炮兵阵地 题目描述 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图 ...

  8. 洛谷P2761 软件补丁问题(状压DP,SPFA)

    题意 描述不清... Sol 网络流24题里面怎么会有状压dp?? 真是狗血,不过还是简单吧. 直接用$f[sta]$表示当前状态为$sta$时的最小花费 转移的时候枚举一下哪一个补丁可以搞这个状态 ...

  9. 洛谷P2831 愤怒的小鸟——贪心?状压DP

    题目:https://www.luogu.org/problemnew/show/P2831 一开始想 n^3 贪心来着: 先按 x 排个序,那么第一个不就一定要打了么? 在枚举后面某一个,和它形成一 ...

随机推荐

  1. Java调用阿里云短信通道服务【千锋】

    这里我们使用SpringBoot 来调用阿里通信的服务. 阿里通信,双11.收到短信,日发送达6亿条.保障力度非常高. 使用的步骤: 1.1. 第一步:需要开通账户 1.2. 第二步:阅读接口文档 1 ...

  2. 设置vs环境

    body, table{font-family: 微软雅黑; font-size: 10pt} table{border-collapse: collapse; border: solid gray; ...

  3. SVN同步时忽略特定文件或文件夹

    在MyEclipse中使用SVN同步的时候,经常会提示一些比如.classpath等不需要同步的配置文件,可以通过设置来忽略这一部分的文件或者文件夹. 1.选择菜单Window→Preferences ...

  4. YourSQLDba介绍

    YourSQLDba介绍 YourSQLDba是一个法国人写的程序,它是由一系列T-SQL存储过程构成的脚本文件.可以理解成一个组件或安装包,从而简化了在Mircorsoft SQL Server 2 ...

  5. java to kotlin (2) - lambda编程

    前言 Kotlin Note 是我学习kotlin整理笔记向博客,文章中的例子参考了kotlin in action这本书籍,同时我也极力推荐这本书,拥有Java基础的人可以很快的就使用kotlin来 ...

  6. HTTP协议篇(一):多工、数据流

    管道机制.多工 管道机制(Pipelining) HTTP 1.1 引入了管道机制(Pipelining),即客户端可通过同一个TCP连接同时发送多个请求.如果客户端需要请求两个资源,以前的做法是在同 ...

  7. 结合Nginx以cgi方式安装php5.5.4

    新建用户及用户组 groupadd webuser useradd -g webuser webuser 下载php-5.5 下载链接:http://pan.baidu.com/s/1i3CBshv ...

  8. 【django之form表单】

    一.构建一个表单 假设你想在你的网站上创建一个简单的表单,以获得用户的名字.你需要类似这样的模板: <form action="/your-name/" method=&qu ...

  9. BZOJ 1856: [Scoi2010]字符串 [Catalan数]

    1856: [Scoi2010]字符串 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1418  Solved: 790[Submit][Status][ ...

  10. BZOJ 2179 [快速傅里叶变换 高精度乘法]

    2179: FFT快速傅立叶 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 3108  Solved: 1599[Submit][Status][Di ...