[VIJOS1197] 费解的开关

Posted sshwy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[VIJOS1197] 费解的开关相关的知识,希望对你有一定的参考价值。

枚举第一行的点击方案。

则点完后剩余的黑灯只能由第二行同一列的点击来弥补

并且第二行除了弥补第一行的黑灯之外,不能点其他灯,否则会使第一行的灯灭

上述构成了递推关系,则递推到最后一行即可。

二进制位运算优化;注意最后一行的状态的判断

复杂度 \(O(n2^n),n=5\).

代码

#include<cstdio>
#include<algorithm>
using namespace std;
int n;
int fl[10];
int bitcount(int x)// 统计 x 的二进制下 1 的个数
    x=(x&0x55555555)+(x>>1&0x55555555);
    x=(x&0x33333333)+(x>>2&0x33333333);
    x=(x&0x0f0f0f0f)+(x>>4&0x0f0f0f0f);
    x=(x&0x00ff00ff)+(x>>8&0x00ff00ff);
    x=(x&0x0000ffff)+(x>>16&0x0000ffff);
    return x;

int main()scanf("%d",&n);
    while(n--)
        int ans=0x3f3f3f3f;
        for(int i=1;i<=5;i++)fl[i]=0;int a;
            for(int j=1;j<=5;j++)scanf("%1d",&a),fl[i]=fl[i]<<1|(a^1);
        //input
        for(int i=0;i<32;i++)// 枚举第一行的点击状态
            int s=i,tot=0,t[10];
            for(int j=1;j<=5;j++)t[j]=fl[j];
            for(int j=1;j<=5;j++)// 枚举每一行
                // 当前行的点击状态为 s,则对于下一行的改变为 t[j+1]^s.
                // 对当前行的改变为 t[j] ^ s<<1^s^s>>1 .
                // 这时,当前行剩下的黑灯即为下一行的点击状态
                t[j]=(t[j]^s<<1^s^s>>1)&((1<<5)-1);
                t[j+1]=(t[j+1]^s)&((1<<5)-1);
                tot+=bitcount(s&((1<<5)-1));
                s=t[j];
            
            if(s==0)ans=min(ans,tot);// 最后一行没有残留的 0
        
        printf("%d\n",ans>6?-1:ans);
    
    return 0;

以上是关于[VIJOS1197] 费解的开关的主要内容,如果未能解决你的问题,请参考以下文章

95. 费解的开关(Acwing)(分析+递推)

AcWing 95 费解的开关

费解的开关

题解AcWing95费解的开关

费解的开关

费解的开关