Flip Game POJ1753 解题报告?【wowkaka】

Flip Game POJ1753解题报告?

一道(入门)状态压缩搜索题(然而newbie的我费了一小时)
具体过程看代码吧
第一次写感觉方法还是十分巧妙的

#include
#include
#define ll long long
using namespace std;
char tab[5][5];//存储棋盘
ll vis[5][5];//判断每个位置有无翻过 
ll res=17;//棋子翻的最终次数  初始化为17是因为总共最多反转16个棋子 最终结果如果还是17则说明没有方案可以把这个棋盘全部翻成白色的(或黑色的); 
ll ans=0;//在某一情况下需要多少步 
int disy[5]={0,0,1,0,-1};//5种情况(还要判断它自身是否翻过
int disx[5]={0,1,0,-1,0};
bool is_black(ll y,ll x){//用来判断i,j点是否是黑色的函数 
	int n=0;
	if(tab[y][x]=='b') n++;//如果i,j是黑色先把n+1
	for(ll i=0;i<=4;i++){//判断上下左右和它本身是否被翻过面 (神奇的做法) 
		if(vis[y+disy[i]][x+disx[i]]==1&&y+disy[i]<=4&&x+disx[i]<=4)
			n++;
	}
	if(n%2==1) return true;//如果是奇数则是黑色返回true 
	return false;//否则不是黑色 
}
void dfsw(ll h){
	ans=0;
	for(ll i=1;i<=4;i++)//在当前状态的刚开始所有棋子都不翻 
		for(ll j=1;j<=4;j++)
			vis[i][j]=0;
	for(ll i=1;i<=4;i++){//发挥 h 的作用,把 h 所表示的数转化为第一层每一位上是否翻转的情况 如0001表示第一行第一个棋子翻,其他不翻 
		if(h&1==1){
			vis[1][i]=1;ans++;
		}
		h>>=1;
	}
	for(ll i=2;i<=4;i++){//判断除第一行以外的棋子需不需要翻面 
		for(ll j=1;j<=4;j++){
			if(is_black(i-1,j)){//如果i,j这个棋子的上面i-1,j是黑色的(或白色的)则翻面 
				vis[i][j]=1;ans++;
			}
		}
	}
	for(ll i=1;i<=4;i++){//判断最后棋盘有没有全变成一种颜色 如果有直接退出 
		if(is_black(4,i))
			return; 
	}
	if(ans<res) res=ans;//如果此答案比总答案小则... res=ans
}
void dfsb(ll h){//全变黑的搜索 同dfsw 
	ans=0;
	ll op=0;
	if(h==0) op=1;
	for(ll i=1;i<=4;i++)
		for(ll j=1;j<=4;j++)
			vis[i][j]=0;
	for(ll i=1;i<=4;i++){
		if(h&1==1){
			vis[1][i]=1;ans++;
		}
		h>>=1;
	}
	for(ll i=2;i<=4;i++){
		for(ll j=1;j<=4;j++){
			if(!is_black(i-1,j)){
				vis[i][j]=1;ans++;
			}
		}
	}
	for(ll i=1;i<=4;i++)
		if(!is_black(4,i))
			return;
	if(ans<res) res=ans;
}
int main(){
	for(ll i=1;i<=4;i++){//读入棋盘数据 
		for(ll j=1;j<=4;j++){
			cin>>tab[i][j];
		}
	}
	for(ll i=0;i<16;i++){//i<16的原因是第一行总共就4个棋子  从0000到1111总共有15种情况 
		dfsw(i);//全变白和全变黑都试一遍 
		dfsb(i);
	}
	if(res==17) {cout<<"Impossible";return 0;}//输出最后的结果 
	cout<<res;
	return 0;
}

你可能感兴趣的:(wowkaka的自毁之路)