zoukankan      html  css  js  c++  java
  • 95.费解的开关

    原题链接:95. 费解的开关



    解题思路:

    在上述规则的01矩阵的点击游戏中,很容易发现三个性质:
    1.每个位置至多被点击一次
    2.若固定了第一行(不能再改变第一行),则满足题意的点击方案至多只有一种。
    其原因是:当第i行某一位为1时,若前i行已经被固定,只能点击第i+1行该位置上的数字才能使得第i行的这一位变成0。从上到下按行使用归纳法可得到上述结论。
    3.点击的先后顺序不影响最终结果
    于是,我们不妨先考虑第一行如何点击。在枚举第一行的点击方法(2的5次方=32种)后,就可以认为第一行“固定不动”,再考虑2-5行如何点击。而按照上述性质2,此时第2-5行的点击方案是确定的————从第一行开始递推,当第i行某一位为1时,点击第i+1行该位置上的数字。若达到第n行时不全为0,说明这种点击方式不合法。在所有合法的点击方式中取点击次数最少的就是答案。对第一行的32次枚举涵盖了该问题的整个状态空间,因此该做法是正确的。
    对于第一行点击方法的枚举,可以采用位运算的方法,枚举0~31这32个5位二进制数,若二进制数的第k(0 <= k < 5)位为1,就点击01矩阵第1行第k+1列数字。

    样例代码:

    #include <bits/stdc++.h>
    using namespace std;
    int n,m,i,j,k,a[7][7],ans1=1e6,b[7][7];//7,7是因为怕在最后一排溢出
    int main()
    {
        int n;
        cin>>n;
        while(n--)
        {
            getchar();
            for (i=1;i<=5;i++)
            {
                for (j=1;j<=5;j++)
                {
                    char ch=getchar();
                    b[i][j]=ch-'0';
                }
                getchar();
            }
            for (i=0;i<=(1<<5);i++)
            {
                for (j=1;j<=5;j++)
                {
                    for (k=1;k<=5;k++)
                        a[j][k]=b[j][k];
                }
                int ans=0;
                for (j=1;j<=5;j++)
                    if (i>>(j-1) & 1)
                    {
                        ans++;
                        a[1][j-1]^=1;
                        a[1][j+1]^=1;
                        a[1][j]^=1;
                        a[2][j]^=1;
                    }
                for (j=1;j<=4;j++)//切记是1~4,而不是2~5,因为我们是控制i+1行,而不是控制第i行
                    for (k=5;k>=1;k--)
                        if (!a[j][k])
                        {
                            ans++;
                            a[j][k]^=1;//上面
                            a[j+2][k]^=1;//下面
                            a[j+1][k]^=1;//本身
                            a[j+1][k+1]^=1;//右面
                            a[j+1][k-1]^=1;//左面
                        }
                //cout<<ans<<endl;
                bool ok=true;
                for (j=1;j<=5;j++)
                    for (k=1;k<=5;k++)
                        if (!a[j][k])
                            ok=false;
                if (ok)
                    ans1=min(ans1,ans);//,cout<<ans<<endl;
            }
            if (ans1>6)
                cout<<-1;
            else
                cout<<ans1;
            ans1=1e7;
            puts("");
        }
        return 0;
    }
    
  • 相关阅读:
    Educational Codeforces Round 67 D. Subarray Sorting
    2019 Multi-University Training Contest 5
    Educational Codeforces Round 69 (Rated for Div. 2) E. Culture Code
    Educational Codeforces Round 69 D. Yet Another Subarray Problem
    2019牛客暑期多校训练第六场
    Educational Codeforces Round 68 E. Count The Rectangles
    2019牛客多校第五场题解
    2019 Multi-University Training Contest 3
    2019 Multi-University Training Contest 2
    [模板] 三维偏序
  • 原文地址:https://www.cnblogs.com/hnkjdx-ssf/p/14156095.html
Copyright © 2011-2022 走看看