ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

状态压缩入门

2019-04-24 16:53:50  阅读:295  来源: 互联网

标签:状态 入门 二进制 vis int 压缩 rep1 ss


洛谷P2622 关灯问题II

关灯问题——状态压缩经典 所谓状态压缩

就是将问题可能遇到的每一个状态用一个唯一的二进制数表示

其复杂度一般都是指数级的 这也注定了状压类的题数据规模都不会太大


此题中我们以1表示开灯状态,0表示关灯状态

这样我们可以以一个长度为n的二进制数唯一的表示每个状态

接着就可以依靠既定的开关关系将每个状态连接起来

通过BFS解决

以灯全开状态为起点

二进制为n个1 ,十进制表示为(1<< n)-1

开始枚举m个开关以得到接下来的m个状态

for(int i=1;i<=m;i++)
{
    ss=(1<< n)-1;
    for(int j=1;j<=n;j++)
    {
        if( a[i][j]==1 && (ss&(1<<j-1)) ) ss^=(1<<j-1);
        else if( a[i][j]==-1 && !(ss&(1<<j-1)) ) ss|=(1<<j-1);
    }      
}

  

ss&(1<< j-1)此运算用以检查当前状态的第j位是否为1

1<< j-1意思是将1左移j-1位,移动后只有第j位上是1

若开关操作为1且当前状态第j位是1

则ss^=(1<< j-1) 表示 1与1异或后得0

若开关操作为-1且当前状态第j位是0

则ss|=(1 << j-1) 表示 1或0 后得1 (此处异或操作也对,因为1异或0得1)

之后便用相同的方法在得到的每个状态上再不断搜索每个状态

由于是BFS,所以一旦某一步状态表示为0(十进制二进制的0写法都是0)

则当前步数必定是最短操作数

若遍历完所有状态都没有0,则输出-1

记得搜索过的状态要打vis标记避免重复访问

#define ll long long 
#define rep1(i,a,b) for(int i=a;i<=b;i++)
#define rep2(i,a,b) for(int i=a;i>=b;i--)
#include <iostream>
#include <queue>
using namespace std;
const int e = (int)105;
int m,n;
int a[e][e];
int vis[1000010];
struct node
{
	int u;
	int s;
};
int bfs(){
	queue<node>q;
	int ss ;
	vis[(1<<n)-1]=1;
	q.push((node){(1<<n)-1,0});
	while(!q.empty()){
		node aa=q.front();
		q.pop();
	//	cout << aa.u << '\n';
		if(aa.u==0)
			return aa.s;
 		rep1(i,1,m){
 			ss=aa.u;
 			rep1(j,1,n){
 			//	cout << aa.u << '\n';
 				if(a[i][j]==1&&(ss&(1<<j-1)))
 					ss^=(1<<j-1);
 				else if(a[i][j]==-1&&!(ss&(1<<j-1)))
 					ss|=(1<<j-1);
 				
 			}
 			if(!vis[ss])
 			{
 			//	cout << aa.u << "***" << '\n';
 				q.push((node) {ss,aa.s+1});
 				vis[ss]=1;
 			}
 		}

	}
	return -1;
}

int main(int argc, char const *argv[])
{
	ios::sync_with_stdio(false);
	cin >> n >> m;
	rep1(i,1,m){
		rep1(j,1,n){
			cin >> a[i][j];
		}
	}
	cout << bfs() << '\n';
	return 0;
}

  

标签:状态,入门,二进制,vis,int,压缩,rep1,ss
来源: https://www.cnblogs.com/bestcoder-Yurnero/p/10763182.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有