zoukankan      html  css  js  c++  java
  • POJ 2965 The Pilots Brothers' refrigerator【BFS+状压 Or 脑洞】

    题目链接:

    http://poj.org/problem?id=1753

    题意:

    给定冰箱门的开关情况,改变一个门则其所在行列的门都会发生改变,求出改变门的最少操作使得最终所有门都是打开状态。

    代码:

    bfs+状态压缩很容易想到~~
    这里的状态压缩要需要多加小心,注意一下存储的是翻转门的情况~

    #include<iostream>
    #include<cstdio>
    #include<queue>
    using namespace std;
    typedef pair<int, int> p;
    const int maxn = 1<<17;
    struct node
    {
        int value;
        int step;
    };
    int pos[maxn];
    int vis[maxn];
    int x[maxn], y[maxn];
    node sta;
    int pa[maxn];
    int dir[16] = {
        0xf888, 0x8f88, 0x88f8, 0x888f, 0xf444, 0x4f44, 0x44f4, 0x444f,
        0xf222, 0x2f22, 0x22f2, 0x222f, 0xf111, 0x1f11, 0x11f1, 0x111f
    };
    int bfs()
    {
        queue<node>q;
        vis[sta.value] = 1;
        sta.step = 0;
        pa[sta.value] = -1;
        q.push(sta);
        while(!q.empty()){
            node t = q.front();q.pop();
            if(!t.value)  return t.step;
            for(int i = 0; i < 16; i++){
                node n;
                n.value = t.value ^ dir[i];
                if(vis[n.value]) continue;
                vis[n.value] = 1;
                pa[n.value] = t.value;
                n.step = t.step + 1;
                pos[n.value] = i;
                q.push(n);
             }
        }
        return -1;
    }
    int main (void)
    {
        char c;
        for(int i = 0; i < 4; i++){
            for(int j = 0; j < 4; j++){
                scanf("%c",&c);
                if(c== '+') sta.value |= 1<<(15- i * 4 - j);
            }
            getchar();
        }
    
        int res = bfs();
        int va = 0;
        for(int i = 0; i < res; i++){
             x[i] = pos[va] % 4 + 1;
             y[i] = pos[va] /4 + 1;
             va = pa[va];
        }
        printf("%d
    ",res);
        for(int i = res - 1; i >= 0; i--)
            printf("%d %d
    ", x[i], y[i]);
        return 0;
    
    }
    

    分析:

    脑洞做法:

    首先观察样例,发现关门的在(1,2)(4,2),而样例却把他们所在行和列的全部翻了一遍。试想,对于某一点(1,2)来说,行和列的元素都翻一遍的话, (1,2)改变了7次,行列元素改变4次,而其他元素改变2次~~也就是说实际上只有(1,2)的状态改变了。把所有行列的元素翻一遍,记录翻动次数,统计翻转过后依然不满足的有多少个,直接翻转这些就好了~至于这道题因为(1,2)(4,2)本身在同一列~所以最后翻动次数为偶数~相当于没有动,就可以不翻转他们了~

    #include<iostream>
    using namespace std;
    const int maxn = 10;
    int a[maxn][maxn];
    int m[maxn][maxn];
    int row[maxn], cal[maxn];
    int main (void)
    {
        char c;
        for(int i = 0; i < 4; i++){
            for(int j = 0; j < 4; j++){
                cin>>c;
                a[i][j] = (c=='-')?0:1;
            }
        }
        for(int i = 0; i <4 ;i++){
            for(int j = 0; j < 4; j++){
                if(!a[i][j]) continue;
                for(int k = 0; k < 4; k++){
                    m[i][k]++;
                    m[k][j]++;
                }
            }
        }
        int res = 0;
        for(int i = 0; i < 4; i++){
            for(int j = 0; j < 4; j++){
                if((m[i][j] + a[i][j])&1){
                    row[res] = i;
                    cal[res++] = j;
                }
            }
        }
        cout<<res<<endl;
        for(int i = 0; i < res; i++)
            cout<<row[i] + 1<<' '<<cal[i] + 1<<endl;
        return 0;
    
    }
    

    这种方格上玩一个方块动会对周围的方块产生影响之类的问题,适合用奇偶表示翻转状态~~~


    遇见问题还是要多思考多观察~~不要硬碰硬,说不定会有更巧妙的方法~

  • 相关阅读:
    BZOJ 3529 数表
    BZOJ 3832 Rally
    BZOJ 1086 王室联邦
    BZOJ 2738 矩阵乘法
    2656565
    小L的区间求和
    小L的直线
    Co-prime 杭电4135
    POJ 跳蚤
    B
  • 原文地址:https://www.cnblogs.com/Tuesdayzz/p/5758706.html
Copyright © 2011-2022 走看看