95. 费解的开关

  1. 每个位置至多只会被点击一次
  2. 若固定了第一行,则满足题意的点击方案至多只有一种。原因:当第i行某一位为1时,若前i行已被固定,只能点击第i+1行该位置上的数字才能使第i行的这一位变成0,从上到下使用归纳法可得上述结论。
  3. 点击的先后顺序不影响最终结果。

于是,我们不妨先考虑第一行如何点击。在枚举第一行的点击方案后,就可以认为第一行固定不动,在考虑2 ~ 5行如何点击。而按照上述性质2,此时第2 ~ 5行的点击方案是确定的。

若到达第n行是不全为1,说明这种点击方式不合法。在所有合法的点击方式中取点击次数最少的就是答案。

const int N=5;
char g[N][N];
char tmp[N][N];

void change(int x,int y)
{
    for(int i=0;i<5;i++)
    {
        int a=x+dx[i],b=y+dy[i];
        if(a>=0 && a<5 && b>=0 && b<5)
            tmp[a][b]='0'+(tmp[a][b]-'0')^1;
    }
}

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        for(int i=0;i<5;i++) scanf("%s",g[i]);

        int res=INF;
        for(int s=0;s<(1<<5);s++)
        {
            memcpy(tmp,g,sizeof g);
            int step=0;
            for(int i=0;i<5;i++)
                if(s >>i & 1)
                {
                    step++;
                    change(0,i);
                }


            for(int i=1;i<5;i++)
                for(int j=0;j<5;j++)
                    if(tmp[i-1][j] == '0')
                    {
                        change(i,j);
                        step++;
                    }

            bool ok=true;
            for(int i=0;i<5;i++)
                if(tmp[4][i] == '0')
                {
                    ok=false;
                    break;
                }
            if(ok) res=min(res,step);
        }
        if(res > 6) res=-1;
        cout<<res<<endl;
    }
    //system("pause");
    return 0;
}

原文地址:https://www.cnblogs.com/fxh0707/p/14507540.html