zoukankan      html  css  js  c++  java
  • 洛谷P2622 关灯问题II 题解

    洛谷P2622

    tag:状态压缩

    【题目大意】

    n个灯,m个按钮,每个按钮都可以控制所有灯,给出每个按钮对每个灯的影响,求从全开到全关的最短步数。

    【题目分析】

    每盏灯只有两个状态,即开与关,记为0和1,则所有灯的状态总数为2^n(n=3时,有000,001,010,100……)

    对每个状态单独分析,可以把每个开关看作一条有向边,这样把不同的状态连起来(也可能出现自环),因此,此题就变成了最短路问题,可以广搜解决。

    接下来要考虑的是如何将按钮变成边,即如何确定经过按钮的操作,当前状态将转变成哪个状态。

    回想二进制操作(与、或、非、抑或),经过尝试,我们发现“与”操作可以帮助我们解决关灯问题。比如:当原状态为100时(1表示开灯,0关),按钮1可以让1和3号灯关上,我们就可以令按钮1等于010.

    100&010=000

    “或”操作可以解决开灯问题,如:原状态为110,按钮2可以让1和3打开

    110|101=111

    当按钮3可以让1和3关上,让2打开时,就可以与010,或010,顺序不会影响结果。

    【代码实现】

    将二进制直接放到数组里?这是不现实的,所以还是用十进制来实现。

    如何提取其中的一位呢?

    a & (1<<j)

    表示提取a的第j位,若结果是0,说明为0,若结果不为0,说明是1。

    标程

    #include<bits/stdc++.h>//2622
    using namespace std;
    int n , m , state[1200];//n<=10,所以前1023是有用的   表示到达i状态需要走的步数 
    int trans[1200][105]; //trans[i][j]表示对状态i按下按钮j的状态 
    int q[1200000],now;//q代表即将处理的队列 
    int temp,open[110],close[110];
    int main()
    {
    	int l=1,r=1; 
    	scanf("%d%d", &n ,&m);
    	for( int i = 1 ; i <= m ; i++)  close[i] = (1<<n)-1;//open[i]=0; 
    	q[1] = (1<<n)-1;//初始状态:所有灯都开着,每一位都是1 
    	for(int i = 0 ; i <= (1<<n) ; i++)  state[i]=-1;//所有状态初始化-1,表示之前没有遍历到这个状态 
    	state[(1<<n)-1]=0;// 当前位置不需要移动就可以到达 
    	for(int i = 1; i <= m ; i++)//m个按钮 
    	  for(int j =1 ; j <= n ; j++){//每个按钮对灯j的控制情况 
    		scanf("%d", &temp);
    		if( temp == 1 )  close[i] -= (1<<(j-1));//按钮i可以让灯j关上 
    		if( temp == -1 ) open[i] += (1<<(j-1));//打开 
    		}
    	for( int i = 0 ; i < (1<<n); i++ )//枚举从000到111的所有状态 
    		for( int j =1 ; j<= m ; j++)//枚举每一个按钮 
    		 trans[i][j] = ( i & close[j] ) | open[j];//经过按钮j,i会变成trans[i][j] 
    
    	while( l <= r ){//当队列中还有任务时 
    	    if(state[0]!=-1) break;
    		now=q[l];
    		l++;
    		for(int i = 1 ; i <= m ; i++){//对于每一个按钮 
    			if( state[trans[now][i]] == -1 ){//如果没有到过这个状态 
    				state[trans[now][i]] = state[now]+1;//这个状态可以由now状态走一步得到 
    				q[++r] = trans[now][i];//准备处理这个状态 
    			}
    		} 
    	}
    	cout<<state[0]<<endl;//到0状态需要走的步数 
    	return 0;
    }
    
  • 相关阅读:
    php的webservice的soapheader认证问题
    训练与解码
    ajax 图片上传
    js倒计时
    数据分析有价值的博客
    [Luogu P5675][GZOI2017]取石子游戏
    [BZOJ4558/LOJ2025/Luogu3271][GZOI2016/JLOI2016/SHOI2016]方
    [BZOJ4557/LOJ2024/Luogu3267][GZOI2016/JLOI2016/SHOI2016]侦察守卫
    PKUWC2019游记
    随机带权选取文件中一行 分类: linux c/c++ 2014-06-02 00:11 344人阅读 评论(0) 收藏
  • 原文地址:https://www.cnblogs.com/erutsiom/p/9904656.html
Copyright © 2011-2022 走看看