Flip Game(状态压缩+深搜)优化时间复杂度
黑白棋翻转问题
题目描述
在一个4x4的棋盘上放有16枚一面黑一面白的棋子。
每次操作时,你可以选择一枚棋子,然后将这枚棋子以及它上下左右相邻的棋子(如果有的话)翻面(颜色反转)。
给定棋盘初始的样子,请问在一些操作后,是否可以将所有棋子都变成一个颜色?如果可以的话,最少需要多少步?
输入
输入包括4行,每行4个字母,用来描述棋盘初始的状态。字母只可能是b或者w,b代表白色朝上,w代表黑色朝上。
输出
包括一行,如果能让所有棋子变成一个颜色,输出所需要的最短步数;如果没有解,输出Impossible。
样例输入
bwwb
bbwb
bwwb
bwww
样例输出
4
题目大意
有一个n*m的格子,每个格子都有黑白两面(0表示白色,1表示黑色)。我们需要把所有的格子都反转成黑色,每反转一个格子,它上下左右的格子都会跟着反转。请求出用最小步数完成反转时每个格子反转的次数。若无解输出Impossible。
题目思想
将wb转换成01——方便change()
先按字典顺序枚举第一行的全部可能,再去推第2行,第3行……把这些行全部推成0(1),最后看最后一行,如果最后一行都是0(1),则成功,记录翻转次数。否则失败。优化时间复杂度2^n方 变成 2^n
第一次使用memcpy
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include <cstdlib>
#define mem(a,x) memset(a,x,sizeof(a))
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
typedef long long ll;
typedef unsigned long long ull; // %llu
const double PI = acos(-1.0);
const double eps = 1e-6;
const int INF = -1u>>1;
const int maxn = 1e5+10;
char s[10][10];
int num[10][10],num2[10][10];
int ans=maxn;
void change(int i,int j) //01变换函数
{
num[i][j]=!num[i][j];
num[i+1][j]=!num[i+1][j];
num[i-1][j]=!num[i-1][j];
num[i][j+1]=!num[i][j+1];
num[i][j-1]=!num[i][j-1];
}
bool check() //检查最后一行是否符合条件
{
int ans=0;
for(int i=1; i<=4; i++)
ans+=num[4][i];
if(ans==4||ans==0)
return 1;
return 0;
}
int turn(int x) //转变2-n行的棋子 假设x=1 即全变成1,对于第i行第j个的转变状态已经确定,若第i-1行第j个为0,(i,j)变,为1则不变。递推到最后一行.
{
int sum=0;
for(int i=2; i<=4; i++)
{
for(int j=1; j<=4; j++)
{
if(num[i-1][j]==x)
{
change(i,j);
sum++;
}
}
}
if(check())
return sum;
return maxn;
}
void f(int sum) //第一行转变状态确定后 存图到num2 操作完成后取图回num。
{
memcpy(num2,num,sizeof(num)); //存图记录下来
int a=turn(1);
memcpy(num,num2,sizeof(num2)); //取图
int b=turn(0);
ans=min(ans,sum+min(a,b)); //sum为第一行变换次数,min(a,b)为2-n行变换最小的次数
memcpy(num,num2,sizeof(num2)); //复原图
}
void dfs(int i,int sum) //递归
{
if(i==5)
{
f(sum);
return ;
}
dfs(i+1,sum);
change(1,i);
dfs(i+1,sum+1);
change(1,i);
}
int main()
{
for(int i=1; i<=4; i++) scanf("%s",s[i]+1);
for(int i=1; i<=4; i++) //初始化
for(int j=1; j<=4; j++)
if(s[i][j]=='b') num[i][j]=0;
else num[i][j]=1;
dfs(1,0);
if(ans>16)
cout<<"Impossible"<<"\n";
else
cout<<ans<<"\n";
}