【模拟+递归+位运算】POJ1753-Flip Game

由于数据规模不大,利用爆搜即可。第一次用位运算写的,但是转念一想应该用递归更加快,因为位运算没有剪枝啊(qДq )

【思路】

位运算:时间效率较低(172MS),有些辜负了位运算的初衷。首先将二维数组倒序看作一个二进制数num。我们假设1代表翻转,0代表不翻转,可以发现以下规律:0 xor 1=1,1 xor 1=0;0 xor 0=0,1 xor 0=1,恰巧满足异或运算。我们假设另一个二进制数i∈[0,2^16),通过异或运算就可以模拟出所有清形。

用check和i进行&操作可以求出以哪些位置为中心进行翻转。假设当前要翻转的方格在二进制数num中所在位数为k,则翻转它时同时翻转的四个方格(假设存在的话)分别为(k-1),(k+1),(k-4),(k+4),则turn[k]=在这几位为1,其余均为0的二进制数,我在草稿纸上手工计算之后直接设在数组中。这样的好处在于,用turn与now直接进行异或操作,即可求出翻转后的情形。

之后通过求i的二进制中1的个数即可。这步操作有一个较为简便的方法,通过草稿纸上模拟就可以领悟。

 1 {
 2     int count = 0;
 3
 4     while(x)
 5     {
 6         x = x & ( x - 1 );
 7         count++;
 8     }
 9     printf("count = %d/n", count);
10 }

上述方法非常实用,要牢记。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 const int INF=100000;
 6 int num,min;
 7 int check[16]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
 8 int turn[16]={18,37,74,132,289,594,1188,2120,4624,9504,19008,33920,8448,20992,41984,18432};
 9
10 void init()
11 {
12     int k=1;
13     for (int i=0;i<4;i++)
14     {
15         for (int j=0;j<4;j++)
16         {
17             char c;
18             scanf("%c",&c);
19             if (c==‘w‘) num+=k;
20             k*=2;
21         }
22         getchar();
23     }
24 }
25
26 int mainprocess()
27 {
28     int min=INF;
29     for (int i=0;i<65535;i++)
30     {
31         int now=num^i;
32         for (int j=0;j<16;j++)
33             if (check[j]&i)
34             {
35                 now=now^turn[j];
36             }
37         if (now==0 || now==65535)
38         {
39             int ans=0,x=i;
40             while (x)
41             {
42                 x=x & (x-1);
43                 ans++;
44             }
45             if (ans<min) min=ans;
46         }
47     }
48     if (min==INF) return -1;
49         else return min;
50 }
51
52 int main()
53 {
54    init();
55    int output=mainprocess();
56    if (output==-1) cout<<"Impossible"; else cout<<output;
57    cout<<endl;
58    return 0;
59 }

此外还可以通过递归+剪枝来完成,效率较高(47ms),计算量较小。值得注意的是c++中如果将数组传入子程序,传入的其实是地址。所以必须在子程序中设置临时数组来保存当前状态,回溯时再还给原来的数组。注意,这个临时数组必须在子程序中,我第一次写的时候误将它写在了主程序中,那么临时数组就完全失去了它的意义。

剪枝:如果当前情况下需要翻转的次数已经小于最小值,则递归不需要再继续。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 using namespace std;
 5 const int INF=100000;
 6 int map[4][4];
 7 int dx[4]={0,0,1,-1};
 8 int dy[4]={1,-1,0,0};
 9 int ans;
10
11 void recurrence(int step,int turn)
12 {
13     int tempmap[4][4];
14     if (turn>=ans) return;
15     if (step==16)
16     {
17         int sum=0;
18         for (int i=0;i<4;i++)
19             for (int j=0;j<4;j++) sum+=map[i][j];
20         if (sum==0 || sum==16) ans=turn;
21     }
22     else
23     {
24         for (int k1=0;k1<4;k1++)
25             for (int k2=0;k2<4;k2++) tempmap[k1][k2]=map[k1][k2];
26
27         for (int i=0;i<2;i++)
28         {
29             if (i==1)
30             {
31                 int x=step/4,y=step%4;
32                 map[x][y]=1-map[x][y];
33                 for (int d=0;d<4;d++)
34                     if (x+dx[d]>=0 && x+dx[d]<4 && y+dy[d]>=0 && y+dy[d]<4) map[x+dx[d]][y+dy[d]]=1-map[x+dx[d]][y+dy[d]];
35             }
36             recurrence(step+1,turn+i);
37             for (int k1=0;k1<4;k1++)
38                 for (int k2=0;k2<4;k2++) map[k1][k2]=tempmap[k1][k2];
39         }
40     }
41 }
42
43 int main()
44 {
45     ans=INF;
46     for (int i=0;i<4;i++)
47     {
48         char c;
49         for (int j=0;j<4;j++)
50         {
51             scanf("%c",&c);
52             if (c==‘w‘) map[i][j]=1; else map[i][j]=0;
53         }
54         getchar();
55     }
56     recurrence(0,0);
57     if (ans!=INF) cout<<ans<<endl;else cout<<"Impossible"<<endl;
58 }
时间: 2024-10-10 16:30:54

【模拟+递归+位运算】POJ1753-Flip Game的相关文章

算法学习 - 递归与非递归,位运算与乘除法速度比较

递归调用非递归调用 运行时间比较 结论 位运算与乘除法 结论 递归调用/非递归调用 我们都知道,很多算法,都是用递归实现的.当然它们同时也是可以用非递归来实现. 一般我们在对二叉树进行遍历的时候,还有求斐波那契数的时候,递归是非常简单的.代码容易懂,好实现. 但是递归的时候,有一个问题,就是需要压栈.为什么要压栈呢?因为当我在函数内部调用自身的时候,要中断当前的操作继续跳转到下一次的实现,而当前运行的状态要保存起来.所以就把当前状态进行压栈,等到运行到递归条件结束的时候,再弹栈. 所以递归就是需

UVa 818Cutting Chains (暴力dfs+位运算+二进制法)

题意:有 n 个圆环,其中有一些已经扣在一起了,现在要打开尽量少的环,使所有的环可以组成一条链. 析:刚开始看的时候,确实是不会啊....现在有点思路,但是还是差一点,方法也不够好,最后还是参考了网上的题解,大神们的代码就是不一样, 但还是看了好久才看懂.首先是用二进制法进行暴力,因为 n 最大才是15,不会超时的,然后就是在暴力时判断打开这些环时,剩下的是不是还存在环, 如果存在那么不是不行的,然后再判断是不是有的环有两个分支以上,因为一个环如果成链那么最多只有两个分支,所以多于两个的也是不对

hdu 3257 Hello World!(位运算 &amp; 模拟)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3257 Hello World! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 476    Accepted Submission(s): 180 Problem Description Your task is to print ...

[ACM] POJ 1753 Flip Game (枚举,BFS,位运算)

Flip Game Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 29921   Accepted: 12975 Description Flip game is played on a rectangular 4x4 field with two-sided pieces placed on each of its 16 squares. One side of each piece is white and the

[模拟]位运算实现加减法

1 /* 2 * 单位加:找与+对应的位运算,分析真值表得出是按位异或^ 3 * 进位:可以用<<进行,但是要判断是否存在进位操作,则需要&来判断. 4 * 加的操作执行到不进位为止,代码如下: 5 * 6 */ 7 LL quickadd(int x, int y) { 8 int xr = x ^ y; //加 9 int nd = x & y; //统计进位 10 while(nd) { 11 int xr1 = xr; 12 int nd1 = nd <<

poj 2799 IP Networks 模拟 位运算

poj链接:http://poj.org/problem?id=2799 这题实在是非常的有趣... 写的时候也非常的开心... 然后就写跪了... 刚好讲了ip地址和子网掩码的只是 整个学期的通信导论我就只有这节课有事没去结果昨晚把这方面的只是补起来了有种功德圆满的感觉 network address是前(32-n)随意 后n位全零 network mask是前(32-n)全一 后n位全零 其次是练习了各种移位操作 我发现移位操作是个非常好用的东西 因为它自填充0 所以对一个二进制数往右移8位

【NOIP模拟题】“与”(位运算)

因为是与运算,所以我们可以贪心地每次找最高位的,将他们加入到新的序列中,然后每一次在这个新的序列继续找下一个位. 然后最后序列中任意两个的与运算的值都是一样的且是最大的. #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> #include <queue&g

位运算 使用技巧

位运算简介及实用技巧(一):基础篇 什么是位运算? 程序中的所有数在计算机内存中都是以二进制的形式储存的.位运算说穿了,就是直接对整数在内存中的二进制位进行操作.比如,and运算本来是一个逻辑运算符,但整数与整数之间也可以进行and运算.举个例子,6的二进制是110,11的二进制是1011,那么6 and 11的结果就是2,它是二进制对应位进行逻辑运算的结果(0表示False,1表示True,空位都当0处理): 110 AND 1011 ---------- 0010  -->  2 由于位运算

POJ1753——Flip Game

Flip Game Description Flip game is played on a rectangular 4x4 field with two-sided pieces placed on each of its 16 squares. One side of each piece is white and the other one is black and each piece is lying either it's black or white side up. Each r