zoukankan      html  css  js  c++  java
  • poj2965 The Pilots Brothers' refrigerator

    题目链接:http://poj.org/problem?id=2965

    分析:1.这道题和之前做的poj1753题目差不多,常规思路也差不多,但是除了要输出最少步数外,还要输出路径。做这道题的时候在怎么输出bfs的路径上卡了下,然后为了方便输出试用dfs写了下,结果TLE了。T^T(不开森....

    2.还有个地方调bug调了挺久的,bfs里面记录路径的时候要记录当前状态的上一个状态,结果没有判断这个状态是否加入队列过就直接改变了,见代码注释处。

    3.重点是会写bfs记录路径了。

    4.听说这道题有大牛的写法,去瞅了瞅,果然牛掰啊。高手思路:

    > 证明:要使一个为'+'的符号变为'-',必须其相应的行和列的操作数为奇数;可以证明,如果'+'位置对应的行和列上每一个位置都进行一次操作,则整个图只有这一'+'位置的符号改变,其余都不会改变.
    > 设置一个4*4的整型数组,初值为零,用于记录每个点的操作数,那么在每个'+'上的行和列的的位置都加1,得到结果模2(因为一个点进行偶数次操作的效果和没进行操作一样,这就是楼上说的取反的原理),然后计算整型数组中一的
    > 个数即为操作数,一的位置为要操作的位置(其他原来操作数为偶数的因为操作并不发生效果,因此不进行操作)
    *********************************
    此上证其可以按以上步骤使数组中值都为‘-’
    ********************************
    在上述证明中将所有的行和列的位置都加1后,在将其模2之前,对给定的数组状态,将所有的位置操作其所存的操作数个次数,举例,如果a[i][j]==n,则对(i,j)操作n次,当所有的操作完后,即全为‘-’的数组。
    其实就是不模2的操作,作了许多的无用功。
    以上的操作次序对结果无影响,如果存在一个最小的步骤,则此步骤一定在以上操作之中。(简单说下:因为以上操作已经包含了所有可改变欲改变位置的操作了)
    而模2后的操作是去掉了所有无用功之后的操作,此操作同样包含最小步骤。
    但模2后的操作去掉任何一个或几个步骤后,都不可能再得到全为‘-’的。(此同样可证明:因为操作次序无影响,先进行最小步骤,得到全为‘-’,如果还剩下m步,则在全为‘-’的数组状态下进行这m步操作后还得到一个全为
    ‘-’的数组状态,此只能是在同一个位置进行偶数次操作,与前文模2后矛盾,所以m=0),因此模2后的操作即为最小步骤的操作。

    5.最近总是做位运算的题,发现异或运算真的好强大啊。

    贴自己的代码:(bfs+位运算)

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<queue>
     5 #include<vector>
     6 #include<map>
     7 #include<algorithm>
     8 #include<string>
     9 #include<cstring>
    10 using namespace std;
    11 char mp[10][10];
    12 struct NODE
    13 {
    14     int state,step;
    15 };
    16 NODE no;
    17 int way[111111]={0};
    18 int father[111111]={0};
    19 int is[111111];
    20 int chang[]={63624,62532,61986,61713,36744,20292,12066,7953,35064,17652,8946,4593,34959,17487,8751,4383};
    21 queue<NODE>q;
    22 void bfs(NODE cur)
    23 {
    24     q.push(cur);
    25     is[cur.state]=1;
    26     NODE next;
    27 
    28     while(!q.empty())
    29     {
    30         cur=q.front();
    31         q.pop();
    32         if(cur.state==65535)
    33         {
    34             cout<<cur.step<<endl;
    35             return;
    36         }
    37         for(int i=0;i<16;i++)
    38         {
    39             next.state=cur.state^chang[i];
    40             //next.state=getState(cur.state,i);
    41             next.step=cur.step+1;
    42             if(is[next.state])//要先判断状态是否出现过,再决定是否改变father[]的值
    43                 continue;
    44             father[next.state]=cur.state;
    45             way[next.state]=i;
    46             if(next.state==65535)  //注意要判断
    47             {
    48                 cout<<next.step<<endl;
    49                 for(int j=next.state;j!=no.state;j=father[j])
    50                     cout<<(way[j]/4+1)<<" "<<(way[j]%4+1)<<endl;
    51                 return;
    52             }
    53             q.push(next);
    54             is[next.state]=1;
    55         }
    56     }
    57     return;
    58 }
    59 int main()
    60 {
    61     no.state=0;
    62     no.step=0;
    63     for(int i=0;i<4;i++)
    64     {
    65         cin>>mp[i];
    66         for(int j=0;j<4;j++)
    67         {
    68             if(mp[i][j]=='-')
    69                 no.state+=pow(2,15-4*i-j);
    70         }
    71     }
    72     bfs(no);
    73     return 0;
    74 
    75 }
  • 相关阅读:
    ::before和::after伪元素的用法
    JS中map、some、every、filter方法
    C++多线程,互斥,同步
    RAII
    Proxy 代理
    Decorator 装饰
    TCP和UDP的9个区别是什么
    谈谈自己对面向对象的理解
    C++11多线程
    std::move
  • 原文地址:https://www.cnblogs.com/tristatl/p/5890490.html
Copyright © 2011-2022 走看看