zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    C# IL语法
    设计模式学习笔记(1)之单例模式
    设计模式学习笔记(3)之策略设计模式(Strategy)
    ORACLE与SQL SERVER语法区别
    浅谈测试驱动开发(TDD)
    面向对象的5条基本设计原则
    干法读后感磨练灵魂 提升心志
    Linux系统管理之硬盘管理
    Linux硬件信息采集
    Linux iptables
  • 原文地址:https://www.cnblogs.com/liuyongliu/p/10326679.html
Copyright © 2011-2022 走看看