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;
    }
    
  • 相关阅读:
    CSV
    矛与盾热血江湖实现喊话功能
    IDA 使用小结
    OD 命令行插件支持的命令
    Qt TreeView
    矛与盾内存数据的分析
    Windows 内核 I/O 端口操作
    矛与盾注入到目标进程
    Qt 多级menu
    C# 美元转中文
  • 原文地址:https://www.cnblogs.com/hnkjdx-ssf/p/14156095.html
Copyright © 2011-2022 走看看