zoukankan      html  css  js  c++  java
  • 题解 50920 费解的开关

    题目链接

    在cnblogs查看

    对于每组数据都跑一边bfs可能会TLE

    1.逆向思想+bfs预处理(参考博客

    运用逆向思维,我们可以从灯全亮的状态开始bfs走6步,记录下所有能到达的状态所需步数,相当于预处理,对于每组数据直接输出答案即可。时间复杂度约为O(68408+T*25)(bfs入队68408次)

    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<map>
    using namespace std;
    queue<int> q;
    map<int,int> ans; //注意要用map,如果开ans[1<<25]会MLE,毕竟很多状态是没用的
    int T;
     
    inline int flip(int x,int i) { //将以i为中心的上下左右反转,注意边界判断
        x^=(1<<i);
        if (i%5!=4) x^=(1<<(i+1));
        if (i%5) x^=(1<<(i-1));
        if (i>4) x^=(1<<(i-5));
        if (i<20) x^=(1<<(i+5));
        return x;
    }
     
    int main() {
        scanf("%d",&T);
         
        q.push((1<<25)-1),ans[(1<<25)-1]=1; //全亮的状态
        while(!q.empty()) {
            int x=q.front();
            q.pop();
            if (ans[x]==7) break; //只走6步
            for (int i=0,y; i<25; i++) //枚举反转哪一盏灯
                if (ans[y=flip(x,i)]==0)
                    q.push(y),ans[y]=ans[x]+1;
        }
         
        while(T--) {
            int y=0;
            for (int i=0,x; i<5; i++)
                for (int j=0; j<5; j++)
                    scanf("%1d",&x),y+=x<<(i*5+j); //把矩阵看成二进制数压缩到y里去(当然也可以用数组存储)
            printf("%d
    ",ans[y]? ans[y]-1:-1);
        }
    }
    

    754ms,于是我拿到了运行时间倒数第二

    2.有技巧的枚举(参考博客

    看看本题提交记录,居然有6ms通过的!看看代码,原来是对于每组数据,先枚举第一行反转哪些点,然后固定第一行,通过第二行反转使第一行全亮,同样这样使前4行全亮,再看最后一行是否已经全亮,从而更新答案。时间复杂度约为O(T3120),通过枚举我们实现了质的飞跃。

    (用c++11运行时不知道为什么答案不正确,改为c++14即可)

    #include<cstdio>
    using namespace std;
    int ans,T;
     
    inline int flip(int &x,int i) {
        x^=(1<<i);
        if (i%5!=4) x^=(1<<(i+1));
        if (i%5) x^=(1<<(i-1));
        if (i>4) x^=(1<<(i-5));
        if (i<20) x^=(1<<(i+5));
    }
     
    void check(int x,int p){
        int cnt=0; //反转次数
        for (int i=0;i<5;i++)
         if ((p>>i)&1)
          flip(x,i),++cnt; //根据我们的要求反转第一行
         
        for (int i=0;i<4;i++)
         for (int j=0;j<5;j++) //第一行固定了,再依次通过下一行反转使前4行全亮
          if (!((x>>(i*5+j))&1)){ 
            flip(x,i*5+j+5);
            if (++cnt>=ans)
              return;
          }
           
        if ((x>>20)==31) ans=cnt; //若最后5位全亮则更新答案
    }
     
    int main(){
        scanf("%d",&T);
         
        while(T--){
            int y=0;
            ans=7;
            for (int i=0,x; i<5; i++)
                for (int j=0; j<5; j++)
                    scanf("%1d",&x),y=(y<<1)+x; //把矩阵看成二进制数压缩到y里去
         
            for (int state=0;state<32;state++) check(y,state); //用二进制数state从00000到11111(31),枚举哪些点反转(位上是1则反转)
             
            ans==7 ? puts("-1"):printf("%d
    ",ans);
        }
    }
    
  • 相关阅读:
    tomcat调试页面的时候,不刷新
    $.ajax()方法详解(转)
    Zookeeper简述
    简述Dubbo
    Nginx入门
    Redis入门
    JVM入门
    spring MVC框架入门(外加SSM整合)
    Mybatis框架入门
    Spring+Hibernate+Struts(SSH)框架整合
  • 原文地址:https://www.cnblogs.com/Randolph68706/p/12003434.html
Copyright © 2011-2022 走看看