POJ2965 The Pilots Brothers' refrigerator (精妙方法秒杀DFS BFS)

来源:互联网 发布:淘宝网折800 编辑:程序博客网 时间:2024/05/29 08:58

这题以前做过,当时枚举翻转次数,搜过了,但是用了800+ms,看着人家都两位数甚至0ms,我再次回顾了下这题,虽然这次的精妙方法不是我自己想出来的(毕竟精妙,我还是差的很远呢)

首先这题BFS或者递归枚举的思路都是特别容易TLE的,不TLE的人也是爬过,而且用了不少的修改。

DFS虽然可以优化到二三百ms,但是我不是很认可DFS啊,明明求得是最少的次数,而查到的DFS的代码都是搜到一个解救输出了,感觉不是太对,所以不提。

还有discuss里看到了高斯消元,原谅本渣不懂什么叫高斯消元。

这个方法也是discuss里的高人想出来了,那个上面讲的不是太清楚,所以我再好好的说一下。

首先要知道这个操作,操作偶数次也等于没有操作,操作奇数次等于操作1次,所以状态可以变成0和1,0为没有翻转,没操作,1为操作一次。

其次要证明,如果有一个+,怎么样才能把它翻转到-

要把这个+所在的行和列一共7个位置,全部操作一次,其余6个位置都是翻转了4次,保持不变,而中心的+所在的位置翻转了7次,变为-,如此操作就全都是-了

现在有若干个+,要把他们全部翻成-,就可以这样思考,把这些+逐个操作成-,因为操作这个+所在的行和列,除了中心的符号会变,周围的都不会改变。

所以可以这样想,如果有3个+,你先把第一个+的行列一共7个位置都操作一次,这个+就没了,然后再对第二个+的行列一共7个位置操作一次,以此类推。

这样可以看到,有些位置操作了偶数次,等同于这些位置可以不用操作,操作奇数次的位置等同于操作1次,这样就是最少步骤了(因为每两次操作等于无用功)

这样就归纳出了本题的方法,开一个4*4的数组,全为0,如果输入的矩阵中某位置为+,就把这个位置的行列7个全部操作一次(取反即可0变1,1变0)

把所有的+全部操作完之后,看这个数组中有多少个1,就是需要做多少次操作,为1的位置就是需要操作的坐标。

这样时间复杂度就大大滴降低了,肯定在100ms以内了


还有数组不要开的太小,我那几次WA都是正好开了4啊16啊

#include<iostream>#include<cstdio>using namespace std;int main(){char s[5][5];int mark[5][5];int x[20],y[20];memset(mark,0,sizeof(mark));for(int i=0;i<4;i++) cin>>s[i];for(int i=0;i<4;i++){for(int j=0;j<4;j++){if(s[i][j]=='+'){mark[i][j]=!mark[i][j];//下面的操作中,i,j这个位置翻转了操作了两次,等于没操作,所以上边这里再操作一次,这样让这个位置                                                           也被操作了for(int k=0;k<4;k++){mark[i][k]=!mark[i][k];mark[k][j]=!mark[k][j];}}}}int ans=0;for(int i=0;i<4;i++){for(int j=0;j<4;j++){if(mark[i][j]){x[ans]=i+1;y[ans]=j+1;ans++;}}}printf("%d\n",ans);for(int i=0;i<ans;i++) printf("%d %d\n",x[i],y[i]);return 0;}


0 0
原创粉丝点击