P2622 关灯问题II(状态压缩+BFS)
Posted liuyongliu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2622 关灯问题II(状态压缩+BFS)相关的知识,希望对你有一定的参考价值。
P2622 关灯问题II
参考:状态压缩动态规划 状压DP
位运算例题(结合BFS):P2622 关灯问题II
题目描述
现有n盏灯,以及m个按钮。每个按钮可以同时控制这n盏灯——按下了第i个按钮,对于所有的灯都有一个效果。按下i按钮对于第j盏灯,是下面3中效果之一:如果a[i][j]为1,那么当这盏灯开了的时候,把它关上,否则不管;如果为-1的话,如果这盏灯是关的,那么把它打开,否则也不管;如果是0,无论这灯是否开,都不管。
现在这些灯都是开的,给出所有开关对所有灯的控制效果,求问最少要按几下按钮才能全部关掉。
输入输出格式
输入格式:
前两行两个数,n m
接下来m行,每行n个数,a[i][j]表示第i个开关对第j个灯的效果。
输出格式:
一个整数,表示最少按按钮次数。如果没有任何办法使其全部关闭,输出-1
这题需要对状压及位运算有一定的了解:首先要判断某一位的灯是开的还是关的,才能进行修改。
具体解法是:对队首的某一状态,枚举每一个开关灯操作,记录到达这一新状态的步数(也就是老状态 + 1),若是最终答案,输出,若不是,压入队列。
也就是说:我们把初始状态,用每个操作都试一遍,就产生了许多新的状态,再用所有操作一一操作新状态,就又产生了新的新状态,我们逐一尝试,直到有目标状态为止,这可以通过BFS实现。
所以现在知道为什么状压比较暴力了吧。
位运算:
1,//把第j位改为1 :dp1=dp1|(1<<(j-1));
2,//把第j位改为0 :if( dp1&(1<<(j-1)) ) dp1=dp1^(1<<(j-1));
代码:
1 /***********************************************/ 2 3 int aa[109][109]; 4 5 struct node{ 6 ll dp;//当前步的状态 7 int step;//步数 8 }; 9 10 int vis[2089]; 11 12 int main() 13 { 14 std::ios::sync_with_stdio(false); 15 std::cin.tie(0); 16 int n,m; 17 cin>>n>>m; 18 for(int i=1;i<=m;i++) 19 for(int j=1;j<=n;j++) cin>>aa[i][j]; 20 node a; 21 a.dp=0; 22 for(ll i=n;i>=1;i--){ 23 //初始每一位都为1 24 a.dp=a.dp|(1<<(i-1)); 25 } 26 a.step=0; 27 queue<node>Q; 28 Q.push(a); 29 while(!Q.empty()) 30 { 31 a.dp=Q.front().dp; 32 a.step=Q.front().step; 33 Q.pop(); 34 vis[a.dp]=1;//表示此状态操作过了 35 if(a.dp==0){ 36 cout<<a.step<<endl; 37 return 0; 38 } 39 for(int i=1;i<=m;i++)//每个开关都按一次 40 { 41 ll dp1=a.dp; 42 for(int j=1;j<=n;j++) 43 { 44 if(aa[i][j]==-1){//把第j位改为1 45 dp1=dp1|(1<<(j-1)); 46 } 47 else if(aa[i][j]==1){//把第j位改为0 48 if( dp1&(1<<(j-1)) ) dp1=dp1^(1<<(j-1)); 49 //dp1-=(1<<(j-1));???????? 50 } 51 } 52 node b; 53 b.dp=dp1; 54 b.step=a.step+1; 55 if(vis[dp1]==0){ 56 Q.push(b); 57 } 58 59 } 60 } 61 cout<<-1<<endl; 62 return 0; 63 }
以上是关于P2622 关灯问题II(状态压缩+BFS)的主要内容,如果未能解决你的问题,请参考以下文章