码迷,mamicode.com
首页 > 其他好文 > 详细

飞行员兄弟

时间:2019-07-21 13:34:58      阅读:114      评论:0      收藏:0      [点我收藏+]

标签:代码   没有   ble   飞行员   main   运算   gis   cst   个数   

飞行员兄弟

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

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

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

于是用二进制枚举,将网格图拆行成列,二进制上的每一位对应了网格图上的一个位置是否进行操作(至于怎么对应,按你自己习惯),但是为了快速变换,实现预处理出点击一个位置,会对哪些格子造成改变,直接二进制下的位运算就体现了点击这个位置局面的改变,随便事先统计好每个数二进制位下1的个数,这样就可以做到\(O(2^{16}\times 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\n",ans);
    for(int i(0);i<16;++i)
        if(gzy>>i&1)
            printf("%d %d\n",i/4+1,i%4+1);
    return 0;
}
il void get(char &c){
    while(c=getchar(),c==' '||c=='\n'||c=='\r');
}

飞行员兄弟

标签:代码   没有   ble   飞行员   main   运算   gis   cst   个数   

原文地址:https://www.cnblogs.com/a1b3c7d9/p/11220804.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!