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 }
View Code
原文地址:https://www.cnblogs.com/liuyongliu/p/10326679.html