• 飞行员兄弟


    飞行员兄弟

    给出一个(4 imes 4)的网格图,网格图上的数字由0,1组成,每次操作可以选择一个位置,让该个位置所在的一行上,一列上所有的数字1变为0,0变为1,给出一个初始局面,询问最少的操作让所有数字变为0。

    这是一道类异或问题,因此对于一个位置的重复操作是没有意义的,现在问题转化为对那些位置操作了。

    网格图问题,按行处理的话,注意到一个位置上的改变,引起了每一行的改变,于是无法剪枝,只有16个格子,(2^{16}=65536),不如直接暴力枚举。

    于是用二进制枚举,将网格图拆行成列,二进制上的每一位对应了网格图上的一个位置是否进行操作(至于怎么对应,按你自己习惯),但是为了快速变换,实现预处理出点击一个位置,会对哪些格子造成改变,直接二进制下的位运算就体现了点击这个位置局面的改变,随便事先统计好每个数二进制位下1的个数,这样就可以做到(O(2^{16} imes 16)=1048576)

    参考代码:

    #include <iostream>
    #include <cstdio>
    #define il inline
    #define ri register
    #define li 65536
    #define intmax 0x7fffffff
    using namespace std;
    int t[16],tot[li];
    il void get(char&);
    int main(){
    	for(int i(0),j,k,l;i<4;++i)
    		for(j=0;j<4;++j)
    			for(k=0;k<4;++k)
    				t[i*4+j]|=1<<k+i*4,
    					t[i*4+j]|=1<<j+k*4;
    	for(int i(0),j;i<li;++i)
    		for(j=15;j>=0;--j)
    			if(i>>j&1)++tot[i];
    	char c;int ans(intmax),gzy,s(0);
    	for(int i(0);i<16;++i)
    		get(c),s|=(c=='-'?0:1)<<i;
    	for(int i(0),j,k;i<li;++i){
    		if(tot[i]>=ans)continue;
    		for(j=15,k=s;j>=0;--j)
    			if(i>>j&1)k^=t[j];
    		if(!k)ans=tot[i],gzy=i;
    	}printf("%d
    ",ans);
    	for(int i(0);i<16;++i)
    		if(gzy>>i&1)
    			printf("%d %d
    ",i/4+1,i%4+1);
    	return 0;
    }
    il void get(char &c){
    	while(c=getchar(),c==' '||c=='
    '||c=='
    ');
    }
    
    
  • 相关阅读:
    python文件读取
    python字符串的使用
    需求验证实现
    面向对象思想——面向对象设计原则
    java面试问题整理-垃圾回收
    Java集合类学习-LinkedList, ArrayList, Stack, Queue, Vector
    Java集合类源码学习- Iterabel<T>,Colection<E>,AbstractCollection<E>
    EMF学习,为了实现可扩展可自定义的模型验证
    EMF学习,为了实现可扩展可自定义的模型验证
    Google 云计算中的 GFS 体系结构
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/11220804.html
Copyright © 2020-2023  润新知