飞行员兄弟

Posted a1b3c7d9

tags:

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

飞行员兄弟

给出一个\(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');

以上是关于飞行员兄弟的主要内容,如果未能解决你的问题,请参考以下文章

acwing 116. 飞行员兄弟

116. 飞行员兄弟

12月学习进度13/31——算法竞赛打卡飞行员兄弟

12月学习进度13/31——算法竞赛打卡飞行员兄弟

飞行员兄弟 DFS+枚举

AcWing 飞行员兄弟 二进制枚举