【搜索 模拟】VIJOS_1197 费解的开关

题意

拉灯游戏。我们现在给出一个5*5的矩阵,求出在6步以内完成的最少次数,如果不能在6步以内完成就输出-1。

思路

枚举第一行点击的状态。当第i行的灯需要改变状态时,我们只能点击第i+1行这个点来使它改变,因为前i行是固定的。根据这个性质我们可以模拟点击的地方,最后判断一下有没有还原完成就可以记录一下答案了。

代码

#include
#include
using namespace std;
int t,a[7][7],n,ans;
char c[6];
inline int check(int x)
{
    int r=0,a1[7][7];

    for (int i=1;i<=5;i++)
        for (int j=1;j<=5;j++)
            a1[i][j]=a[i][j];

    for (int i=1;i<=4;i++)//模拟点击
        for (int j=1;j<=5;j++)
        {
            if (!a1[i][j])
            {
                a1[i][j]=1;
                a1[i+1][j]=1-a1[i+1][j];
                a1[i+1][j-1]=1-a1[i+1][j-1];
                a1[i+1][j+1]=1-a1[i+1][j+1];
                a1[i+2][j]=1-a1[i+2][j];
                r++;
            }
        }
    for (int i=1;i<=5;i++)
        if (!a1[5][i]) return 2147483647;//没有还原返回一个大值
    return x+r;//点击次数加上第一行的点击次数
}
void dfs(int dep,int t)//枚举第一行的点击情况,dep代表第一行的第几个点,t代表点击的次数
{
    if (dep>5) 
    {
        ans=min(ans,check(t));//统计答案
        return;
    }
    a[1][dep]=1-a[1][dep];
    a[1][dep-1]=1-a[1][dep-1];
    a[2][dep]=1-a[2][dep];
    a[1][dep+1]=1-a[1][dep+1];//点击就改变了
    dfs(dep+1,t+1);//代表点击
    a[1][dep]=1-a[1][dep];
    a[1][dep-1]=1-a[1][dep-1];
    a[2][dep]=1-a[2][dep];
    a[1][dep+1]=1-a[1][dep+1];//还原
    dfs(dep+1,t);//代表不点
}
int main()
{
    scanf("%d",&n);
    while (n--)
    {
        ans=2147483647;
        for (int i=1;i<=5;i++)
        {
            scanf("%s",c+1);
            for (int j=1;j<=5;j++)
                a[i][j]=c[j]-48;
        }
        dfs(1,0);
        if (ans<7) printf("%d\n",ans);
        else printf("-1\n");
    }
}

你可能感兴趣的:(枚举)