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

    费解的开关

    给出一个(5 imes 5)矩形网格图,(a[i][j])表示第i行第j列的数字(只能为0或者1),每次操作可以选择一个位置,对于该个位置以及其上下左右个一个位置上的数字0变成1,1变成0,询问是否能少于6次将所有数字变为1,如果能,请输出最少次数。

    其实最终变为0还是变为1都无所谓,不妨把网格图中所有数字取反,这样就转换成最后数字要全部变为1,这样方便一些(接下来的行列坐标从0开始)。

    (h[i])为第i行的状态(第k位上1表示表示(a[i][k]=1),反之)。

    注意到问题的异或性,不妨将这类问题称作类异或问题,这样的问题具有一个通性,即异或的交换律和结合律它也满足,于是多次进行一个位置的操作没有意义,而且操作不存在顺序,这样会大大优化我们的搜索。

    因为原题是存在多组数据,而且数据组数还很多,于是接下来直接暴力组合
    (O(C_{25}^6)=177100),会超时

    超时代码

    #include <iostream>
    #include <cstdio>
    #define il inline
    #define ri register
    using namespace std;
    int ans,li((1<<25)-1);
    il void get(char&);
    void dfs(int,int,int);
    template<class free>
    il free Min(free,free);
    int main(){char c;
    	int lsy,s;scanf("%d",&lsy);
    	while(lsy--){s=0;
    		for(int i(0);i<25;++i)
    			get(c),s|=c-48<<i;
    		ans=7,dfs(0,0,s);
    		if(ans==7)puts("-1");
    		else printf("%d
    ",ans);
    	}
    	return 0;
    }
    il void get(char&c){
    	while(c=getchar(),c==' '||c=='
    '||c=='
    ');
    }
    template<class free>
    il free Min(free a,free b){
    	return a<b?a:b;
    }
    void dfs(int a,int b,int c){
    	if(b>=ans)return;
    	if(a==25){
    		if(c==li)ans=Min(ans,b);
    		return;
    	}
    	dfs(a+1,b,c),c^=(1<<a);
    	if(a%5)c^=(1<<a-1);
    	if(a%5<4)c^=(1<<a+1);
    	if(a-5>=0)c^=(1<<a-5);
    	if(a+5<25)c^=(1<<a+5);
    	dfs(a+1,b+1,c);
    }
    
    

    于是我们接下来的搜索要考虑剪支,因为是网格图问题,考虑方向有行列,对角线和矩形,我们按行处理,这样我们每一行只要枚举(2^5=32)次,不妨用枚举二进制代替自由组合,显然时间复杂度(O(32^5)=33554432),加上最优性剪支,即如果超出6或者比最优解大,那么return,这样还不够,注意到我们是按行处理的,如果处理完这一行,下一行一定要将其变为0,否则它以后再也变不回0了,于是加上这个剪支,此题才能过。

    参考代码:

    #include <iostream>
    #include <cstdio>
    #define il inline
    #define ri register
    using namespace std;
    int ans,jm[6],tot[32];
    il void get(char&);
    void dfs(int,int,int,int);
    int main(){char c;
    	int lsy;scanf("%d",&lsy);
    	for(int i(0),j;i<32;++i)
    		for(j=4;j>=0;--j)
    			if(i>>j&1)++tot[i];
    	while(lsy--){ans=7;
    		for(int i(0),j;i<5;++i)
    			for(j=0,jm[i]^=jm[i];j<5;++j)
    				get(c),(c-=48)^=1,jm[i]|=c<<j;
    		dfs(0,0,jm[0],0);
    		if(ans==7)puts("-1");
    		else printf("%d
    ",ans);
    	}
    	return 0;
    }
    void dfs(int h,int l,int r,int c){
    	if(c>=ans)return;
    	if(h==5){if(!l)ans=c;return;}
    	for(int i(0),j,k;i<32;++i){
    		if(h&&i^l)continue;k=r;
    		for(j=4;j>=0;--j)
    			if(i>>j&1){k^=1<<j;
    				if(j)k^=1<<j-1;
    				if(j<4)k^=1<<j+1;
    			}dfs(h+1,k,jm[h+1]^i,c+tot[i]);
    	}
    }
    il void get(char &c){
    	while(c=getchar(),c==' '||c=='
    '||c=='
    ');
    }
    
    
  • 相关阅读:
    Python学习笔记2——数据类型
    Python学习笔记1——环境配置
    Dagger2 探索记3——两大进阶组件(二)
    NLP 计算机视觉 cv 机器学习 ,入们基础
    Android studio 常用快捷键
    uiautomator 1使用简介
    在Android源码中如何吧so库打包编译进入apk, 集成第三方库(jar和so库)
    android框架Java API接口总注释/**@hide*/和internal API
    Google android开发者 中国官方文档开放了呀
    android aidl通信 RemoteCallbackList客户端注册回调
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/11204293.html
Copyright © 2011-2022 走看看