Flip Game(状态压缩+深搜)优化时间复杂度

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";
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值