P2622 关灯问题II
题意
给定n盏灯,以及m个按钮。每个按钮可以同时控制这n盏灯,按下了第i个按钮,对于所有的灯都会有一个效果。按下i按钮对于第j盏灯,是下面3中效果之一:如果a[i][j]为1,那么当这盏灯开了的时候,把它关上,否则不管;如果为-1的话,当这盏灯是关的,把它打开,否则也不管;如果是0,无论这灯是否开,都不管。
现在这些灯都是开的,给出所有开关对所有灯的控制效果,求问最少要按几下按钮才能全部关掉。
n < = 10 , m < = 100 n<=10,m<=100 n<=10,m<=100
思路
用n位二进制数表示这n盏灯的状态,0为关,1为开。
则初始状态为 000000…000。
令 d p [ x ] dp[x] dp[x]表示得到 x x x这个状态需要按下按钮的最小次数,即有 d p [ 0 ] = 0 dp[0] = 0 dp[0]=0。
然后我们从状态0开始,依次按下每个按钮,得到其他状态y,当y状态第一次出现时,就得到了状态y的最小次数,即 d p [ y ] = d p [ x ] + 1 dp[y] = dp[x]+1 dp[y]=dp[x]+1。
当然,如果得不到这个状态,就输出-1。
也可以这么理解,我们把所有的状态看作点,状态之间的转移看作边,则最开始我们有一个状态为0初始点,通过按按钮,我们可以通过该点得到其他点,则在这两点之间连一条边权为1的边,最终,从起点出发,到每个点的最短路就是要获得每个状态的最少次数。但我们没有必要去跑一便最短路,每个点第一个被连接到时所消耗的次数,就是它的最短路。(说白了就是在BFS)
代码
附上两份代码,思路一致,具体实现略有不同。
另外,如果不想自己用位运算提取状态的话,也可以用C++STL的bitset实现。
#include<bits/stdc++.h>
using namespace std