题目描述--->P2622 关灯问题II

没用的话:

首先第一眼看到题,嗯?n<=10?搜索?

满心欢喜地敲了一通搜索。

交上去,Wa声一片?

全部MLE! 这么坑人神奇?

一想,可能是爆栈了 emmm

思考了一番看了下题解&&标签

哦原来是状压DP

情不自禁地分析

n<=10.

最多只有(2<<10)-1=1023种状态

我们完全可以用数组存储状态.

以样例为例: 算了 太辣鸡了,我自己瞎出吧.

如果n=8,即一共有8盏灯.

初始状态它们全开着,我们可以认为是这样的↓
1 1 1 1 1 1 1 1
我们用十进制数(1<<8)-1=255存储这一状态.

此时,如果有一个按钮可以关掉第7个灯(从右向左数).

我们如何做到这一操作?↓

你应该会想到通过位运算操作.
那我们应该 1<< ?才能对应上第七个灯呢? 不妨尝试一下1<<7 是这样↓
1 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 //初始状态
我们发现:哇!到了第8个灯! 所以说我们应该1<<6 得到这样↓
0 1 0 0 0 0 0 0
1 1 1 1 1 1 1 1
这时,我们就可以控制第7个灯了!

你会不会有疑问?(好吧,我强加的

为什么算状态的时候是(1<<n)-1?

而算第i个灯的时候是1<<(i-1)个?

'<<'操作是我们把1进行平移(我思想中的平移

演示一下这个过程.

  0000000001   //某一个2进制下的数
0000000010 //原数<<1
0000000100 //原数<<2
.
.
以此类推.

我们发现,1<<i,我们的1后面就会有i个0

如果1<<n位(这里以8为例)

得到1 0 0 0 0 0 0 0 0
数一下 这一共是9个灯.
-1之后,我们得到这样的东西↓
0 1 1 1 1 1 1 1 1
//这表示一共有8个灯,全部开着.

所以想要计算这是哪一种状态,我们就可以(1<<n)-1了

这样疑问就解决了//如果不理解再回去看看,动手试试


题目三种操作.

如果a[i][j]为1,那么当这盏灯开了的时候,把它关上,否则不管;如果为-1的话,如果这盏灯是关的,那么把它打开,否则也不管;如果是0,无论这灯是否开,都不管。

首先请看清上面三种操作,再向下看

对于操作1,我们难点就在于判断当前状态下这盏灯是否开着.

如果你懂得&操作,那就很简单了!

-----------------介绍一下&---------------

按位与操作,1&0=1,1&1=1,0&0=0;

两边全部是1才为1,否则为0.

-----------------介绍完毕-------------------

&操作可以判断某一位上的灯是否开着.(注意只能是这一位.

如果你会了如何判断这个灯开着,那么关着就是!

这样我们的问题就得以解决了.

设f[i]代表到达i这种状态的最少操作次数.

如何写代码?↓

for(RI i=(1<<n)-1;i>=0;i--)//枚举状态
{
for(RI j=1;j<=m;j++)//枚举开关
{
int now=i;//我们的now最终会变为,按完这个开关后的状态.
for(RI l=1;l<=n;l++)//枚举控制的灯.
{
if(a[j][l]==0)continue;//不操作
if(a[j][l]==1 and (i&(1<<(l-1)))) now^=(1<<(l-1));//第一个操作
if(a[j][l]==-1 and !(i&(1<<(l-1)))) now^=(1<<(l-1));
//第二个操作
}
f[now]=std::min(f[now],f[i]+1);//常规操作,求最小操作次数.
//因为我们可以通过i状态操作按一个开关到达now状态.
//所以是f[i]+1.
}
}

尝试解释一下为什么第一层是枚举状态.

我们的开关可以控制所有状态来得到下一个状态.

而且我们的初始状态是全部开着,需要倒着枚举.直到为0(全部关闭).

所以我们的答案就是f[0].

--------------------代码--------------------

#include<bits/stdc++.h>
#define IL inline
#define RI register int
IL void in(int &x)
{
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
int a[108][18],f[2048],n,m;
int main()
{
in(n),in(m);
memset(f,0x3f,sizeof f);
for(RI i=1;i<=m;i++)
for(RI j=1;j<=n;j++)
in(a[i][j]);
f[(1<<n)-1]=0;//灯全开着的操作次数为0
//printf("%d",(1<<n)-1);
for(RI i=(1<<n)-1;i>=0;i--)
{
for(RI j=1;j<=m;j++)
{
int now=i;
for(RI l=1;l<=n;l++)
{
if(a[j][l]==0)continue;
if(a[j][l]==1 and (i&(1<<(l-1)))) now^=(1<<(l-1));
if(a[j][l]==-1 and !(i&(1<<(l-1)))) now^=(1<<(l-1));
}
f[now]=std::min(f[now],f[i]+1);
}
}
printf("%d",f[0]==1061109567?-1:f[0]);
//这个奇怪的数字就是memset 0x3f得出来的
//并无什么其他意义
}

状压DP【p2622】 关灯问题II的更多相关文章

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

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

  2. P2622 关灯问题II(状压bfs)

    P2622 关灯问题II 题目描述 现有n盏灯,以及m个按钮.每个按钮可以同时控制这n盏灯——按下了第i个按钮,对于所有的灯都有一个效果.按下i按钮对于第j盏灯,是下面3中效果之一:如果a[i][j] ...

  3. 关灯问题II 状压DP

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

  4. [状压DP]关灯问题II

    关 灯 问 题 I I 关灯问题II 关灯问题II 题目描述 现有n盏灯,以及 m m m个按钮.每个按钮可以同时控制这 n n n盏灯--按下了第 i i i个按钮,对于所有的灯都有一个效果.按下i ...

  5. [状压DP]车II

    车 I I 车II 车II 题目描述 有一个 n ∗ m n*m n∗m的棋盘 ( n . m ≤ 80 , n ∗ m ≤ 80 ) (n.m≤80,n*m≤80) (n.m≤80,n∗m≤80)要 ...

  6. HDU 6149 Valley Numer II 状压DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6149 题意:中文题目 解法:状压DP,dp[i][j]代表前i个低点,当前高点状态为j的方案数,然后枚 ...

  7. HDU 6149 Valley Numer II(状压DP)

    题目链接 HDU6149 百度之星复赛的题目……比赛的时候并没有做出来. 由于低点只有15个,所以我们可以考虑状压DP. 利用01背包的思想,依次考虑每个低点,然后枚举每个状态. 在每个状态里面任意枚 ...

  8. 状态压缩动态规划 状压DP

    总述 状态压缩动态规划,就是我们俗称的状压DP,是利用计算机二进制的性质来描述状态的一种DP方式 很多棋盘问题都运用到了状压,同时,状压也很经常和BFS及DP连用,例题里会给出介绍 有了状态,DP就比 ...

  9. 状压DP总结

    状态压缩就是将一行的状态压成一个二进制数,这个数的二进制形式反映了这一行的情况 比如0100111的意义为:这一排的第一个数没被使用,第二个被占用了,第三四个没被占用,第五六七个被占用 我们知道位运算 ...

随机推荐

  1. [bzoj4860] [BeiJing2017]树的难题

    Description 给你一棵 n 个点的无根树.树上的每条边具有颜色. 一共有 m 种颜色,编号为 1 到 m.第 i 种颜色的权值为 ci.对于一条树上的简单路径,路径上经过的所有边按顺序组成一 ...

  2. Notice : brew install php70

    To enable PHP in Apache add the following to httpd.conf and restart Apache: LoadModule php7_module  ...

  3. BZOJ5343 [Ctsc2018]混合果汁 【二分 + 主席树】

    题目链接 BZOJ5343 题解 明显要二分一下美味度,然后用尽量少的价格去购买饮料,看看能否买到\(L\)升,然后看看能否控制价格在\(g\)内 尽量少的价格,就优先先选完便宜的饮料,由于询问的是一 ...

  4. [codeforces/gym/100431/E]KMP关于border的理解

    题目链接:http://codeforces.com/gym/100431/ 考虑到对于一个串β,能cover它的最短的α必然是它的border的某个前缀,或者是这个β本身. 所谓border,就是n ...

  5. ng的ngModel用来处理表单操作

    https://segmentfault.com/a/1190000009126012

  6. wget、yum、rpm、apt-get区别

    wget 类似于迅雷,是一种下载工具, 通过HTTP.HTTPS.FTP三个最常见的TCP/IP协议下载,并可以使用HTTP代理 名字是World Wide Web”与“get”的结合. yum: 是 ...

  7. centos安装net-speeder

    以前介绍过VPS上安装锐速对VPS的加速效果,但是这货对 Linux 内核有要求,一般就只能在XEN或者KVM的机子上安装.不过还好锐速有一个免费的代替品:net-speeder,所以这里介绍一下 D ...

  8. 说明exit()函数作用的程序

    // algo1-4.cpp 说明exit()函数作用的程序 #include"c1.h" int a(int i) { if(i==1) { printf("退出程序的 ...

  9. iOS 全局变量设置的几种方式~

    在iOS开发过程中关于全局变量的几个方法 1. 在APPDelegate中声明并初始化全局变量.AppDelegate可以在整个应用程序中调用,在其他页面中可以使用代码段获取AppDelegate的全 ...

  10. [转]使用 LDAP 组或角色限制访问,包含部分单点登录SSO说明

    参考:http://www-01.ibm.com/support/knowledgecenter/api/content/SSEP7J_10.2.2/com.ibm.swg.ba.cognos.crn ...