Flip Game ZOJ - 2050 POJ-1753 HDU-4146 状态压缩 搜索

都是差不多的意思 zoj给的时间比较多

题意是 一个4x4的棋盘 要求反转为全白或全黑 求最少次数

所有要说的都在代码里了

#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
#define maxn (1<<16)-1
using namespace std;
int visit[maxn+5];
queue<int> q;

int flip(int state,int i,int j)
{
	int a=(1<<(i*4+j));
	state^=a;//按位异或 同则0 异则1 所以除去改变位之外 其他的状态不会变 比如:非改变位:元状态为1 与0异或得1 ;元状态为0与0异或得0 
	if(i-1>=0)
	{
		a=(1<<((i-1)*4+j));
		state^=a;//up		
	}
	if(i+1<4)
	{
		a=(1<<((i+1)*4+j));
		state^=a;//down
	}
	if(j-1>=0)
	{
		a=(1<<(i*4+j-1));
		state^=a;//left
	}
	if(j+1<4)
	{
		a=(1<<(i*4+j+1));
		state^=a;//right
	}
	return state;//忘记return了emm 
}

int bfs(int state)
{
	/*
	这个算法主要流程
	第一层跑出每个翻转的状态  16次 
	第二层在每一个第一遍跑出来的状态的基础上再 跑16次 就是总次数变为16*16
	之后以此类推
	而超过16层之后就相当于又翻回来原来的状态 
	本质上就是优化穷举 穷举的话16^16有一大堆重复状态 这个的话 只有(1<<16) -1的状态量 
	*/
	while(!q.empty()) q.pop();
	q.push(state);
	int step=0;
	visit[state]=1; 
	while(!q.empty())
	{
		int g=q.size();
		for(int k=0;k<g;k++)
		{
			int f=q.front();
			q.pop();
			if(step>16||f==0||f==maxn) return step;//如果 超过16次 0全白 maxn全黑 return 
			for(int i=0;i<4;i++)//在每个状态的基础上 再次枚举所有翻一遍的状况 
			{
				for(int j=0;j<4;j++)
				{									
					int t=flip(f,i,j);
					if(!visit[t])
						q.push(t);												
					visit[t]=1;				
				}
			}
		}
		step++;
	}	
}

int main()
{
	int T;
	cin>>T;
	bool flag1=true;
	while(T--)
	{
	getchar();
	memset(visit,0,sizeof(visit));
	char map[10];
	int k=0,state=0;//state也可以用数组每一行压缩成一个int  
	for(int i=0;i<4;i++)
	{
		scanf("%s",map);
		for(int j=0;j<4;j++)
		{
			if(map[j]=='b')
			state+=(1<<k); 
			k++;//控制位置 
		}
	}
	int ans=bfs(state);//初始状态传入 
		if(!flag1) 
            cout<<endl;
        if(flag1)
        {
            flag1=false;
        }
	if(ans>16) cout<<"Impossible"<<endl;
	else cout<<ans<<endl;

	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_41544329/article/details/82455076