zoukankan      html  css  js  c++  java
  • [POJ2965]The Pilots Brothers' refrigerator (搜索/位运算)

    题意

    游戏“The Pilots Brothers:跟随有条纹的大象”有一个玩家需要打开冰箱的任务。

    冰箱门上有16个把手。每个手柄可以处于以下两种状态之一:打开或关闭。只有当所有把手都打开时,冰箱才会打开。手柄表示为矩阵4х4。您可以在任何位置[i,j](1≤i,j≤4)更改句柄的状态。但是,这也会更改第i行中所有句柄的状态以及第j列中的所有句柄。

    任务是确定打开冰箱所需的最小手柄切换次数。

    思路

    一个和“费解的开关”,"棋盘翻转",这样的位运算的题目很像,只不过这次一次翻转1行+1列

    其实可以用1个数就可以记录状态,但是我懒……

    (其实是不会状压啦)

    Code

    #include<cstdio>
    using namespace std;
    #define max(a,b) (a>b?a:b)
    #define min(a,b) (a<b?a:b)
    
    int x[20], y[20];
    
    int map[6][6];
    int ans=33;
    int ansX[20],ansY[20];
    
    int read()
    {
        char ch = getchar();
        while (ch!='-' && ch!='+') ch = getchar();
        return ch=='-'?1:0;
    }
    
    void build()
    {
        for(int i=0;i<4;i++)
            for (int j = 0; j < 4; j++)
                map[i][j] = read();
    }
    
    void flip(int s)
    {
        int x1 = s / 4;
        int y1 = s % 4;
        for (int i = 0; i < 4; i++)
        {
            map[i][y1] ^= 1;
            map[x1][i] ^= 1;
        }
        map[x1][y1] ^= 1;
    }
    
    bool check()
    {
        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 4; j++)
                if (!map[i][j]) return 0;
        }
        return 1;
    }
    
    void dfs(int s, int b)
    {
        if (check())
        {
            if (ans > b)
            {
                ans = b;
                for (int i = 1; i <= ans; i++)
                    ansX[i] = x[i], ansY[i] = y[i];
            }
            return;
        }
    
        if (s >= 16) return;
        dfs(s + 1, b);
        flip(s);
        x[b + 1] = s / 4 + 1;
        y[b + 1] = s % 4 + 1;
        dfs(s + 1, b + 1);
        flip(s);
        return;
    }
    
    int main()
    {
        build();
        dfs(0, 0);
        printf("%d
    ", ans);
        for (int i = 1; i <= ans; i++)
            printf("%d %d
    ", ansX[i], ansY[i]);
        return 0;
    }

    其他做法

    博客上搜到的

    放出来

    注释也很详细了

    用奇偶性做的

    /*
    
    参考高手的高效解法:
    > 证明:要使一个为'+'的符号变为'-',必须其相应的行和列的操作数为奇数;可以证明,如果'+'位置对应的行和列上每一个位置都进行一次操作,则整个图只有这一'+'位置的符号改变,其余都不会改变.
    > 设置一个4*4的整型数组,初值为零,用于记录每个点的操作数,那么在每个'+'上的行和列的的位置都加1,得到结果模2(因为一个点进行偶数次操作的效果和没进行操作一样,这就是楼上说的取反的原理),然后计算整型数组中一的
    > 个数即为操作数,一的位置为要操作的位置(其他原来操作数为偶数的因为操作并不发生效果,因此不进行操作)
    *********************************
    此上证其可以按以上步骤使数组中值都为‘-’
    ********************************
    在上述证明中将所有的行和列的位置都加1后,在将其模2之前,对给定的数组状态,将所有的位置操作其所存的操作数个次数,举例,如果a[i][j]==n,则对(i,j)操作n次,当所有的操作完后,即全为‘-’的数组。
    其实就是不模2的操作,作了许多的无用功。
    以上的操作次序对结果无影响,如果存在一个最小的步骤,则此步骤一定在以上操作之中。(简单说下:因为以上操作已经包含了所有可改变欲改变位置的操作了)
    而模2后的操作是去掉了所有无用功之后的操作,此操作同样包含最小步骤。
    但模2后的操作去掉任何一个或几个步骤后,都不可能再得到全为‘-’的。(此同样可证明:因为操作次序无影响,先进行最小步骤,得到全为‘-’,如果还剩下m步,则在全为‘-’的数组状态下进行这m步操作后还得到一个全为
    ‘-’的数组状态,此只能是在同一个位置进行偶数次操作,与前文模2后矛盾,所以m=0),因此模2后的操作即为最小步骤的操作。
    */
    #include <iostream>
    using namespace std;
    
    bool mark[4][4];
    char s[4][4];
    
    int main()
    {
        int i,j,k;
        int ci[16],cj[16];
        int nas = 0;
        memset(mark,0,sizeof(mark));
        for(i = 0;i < 4;i++)
            cin >> s[i];
        for(i = 0;i < 4;i++)
            for(j = 0;j < 4;j++)
            {
                char c = s[i][j];
                if(c == '+')
                {
                    mark[i][j] = !mark[i][j];
                    for(k = 0;k < 4;k++)
                    {
                        mark[i][k] = !mark[i][k];
                        mark[k][j] = !mark[k][j];
                    }
                }
    
            }
        for(i = 0;i < 4;i++)
            for(j = 0;j < 4;j++)
                if(mark[i][j] == true)
                {
                    ci[nas] = i + 1;
                    cj[nas] = j + 1;
                    nas ++;
                }
        printf("%d
    ",nas);
        for(i = 0;i < nas;i++)
        {
            printf("%d %d
    ",ci[i],cj[i]);
        }
        return 0;
    }
  • 相关阅读:
    hive与hbase整合
    待重写
    hive DML
    【知识强化】第六章 总线 6.1 总线概述
    【知识强化】第五章 中央处理器 5.1 CPU的功能和基本结构
    【知识强化】第四章 指令系统 4.3 CISC和RISC的基本概念
    【知识强化】第四章 指令系统 4.2 指令寻址方式
    【知识强化】第四章 指令系统 4.1 指令格式
    【知识强化】第三章 存储系统 3.6 高速缓冲存储器
    【知识强化】第三章 存储系统 3.5 双口RAM和多模块存储器
  • 原文地址:https://www.cnblogs.com/lincold/p/10123861.html
Copyright © 2011-2022 走看看