【模拟+递归+位运算】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的个数即可。这步操作有一个较为简便的方法,通过草稿纸上模拟就可以领悟。
{
int count = ; while(x)
{
x = x & ( x - );
count++;
}
printf("count = %d/n", count);
}
上述方法非常实用,要牢记。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int INF=;
int num,min;
int check[]={,,,,,,,,,,,,,,,};
int turn[]={,,,,,,,,,,,,,,,}; void init()
{
int k=;
for (int i=;i<;i++)
{
for (int j=;j<;j++)
{
char c;
scanf("%c",&c);
if (c=='w') num+=k;
k*=;
}
getchar();
}
} int mainprocess()
{
int min=INF;
for (int i=;i<;i++)
{
int now=num^i;
for (int j=;j<;j++)
if (check[j]&i)
{
now=now^turn[j];
}
if (now== || now==)
{
int ans=,x=i;
while (x)
{
x=x & (x-);
ans++;
}
if (ans<min) min=ans;
}
}
if (min==INF) return -;
else return min;
} int main()
{
init();
int output=mainprocess();
if (output==-) cout<<"Impossible"; else cout<<output;
cout<<endl;
return ;
}
此外还可以通过递归+剪枝来完成,效率较高(47ms),计算量较小。值得注意的是c++中如果将数组传入子程序,传入的其实是地址。所以必须在子程序中设置临时数组来保存当前状态,回溯时再还给原来的数组。注意,这个临时数组必须在子程序中,我第一次写的时候误将它写在了主程序中,那么临时数组就完全失去了它的意义。
剪枝:如果当前情况下需要翻转的次数已经小于最小值,则递归不需要再继续。
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int INF=;
int map[][];
int dx[]={,,,-};
int dy[]={,-,,};
int ans; void recurrence(int step,int turn)
{
int tempmap[][];
if (turn>=ans) return;
if (step==)
{
int sum=;
for (int i=;i<;i++)
for (int j=;j<;j++) sum+=map[i][j];
if (sum== || sum==) ans=turn;
}
else
{
for (int k1=;k1<;k1++)
for (int k2=;k2<;k2++) tempmap[k1][k2]=map[k1][k2]; for (int i=;i<;i++)
{
if (i==)
{
int x=step/,y=step%;
map[x][y]=-map[x][y];
for (int d=;d<;d++)
if (x+dx[d]>= && x+dx[d]< && y+dy[d]>= && y+dy[d]<) map[x+dx[d]][y+dy[d]]=-map[x+dx[d]][y+dy[d]];
}
recurrence(step+,turn+i);
for (int k1=;k1<;k1++)
for (int k2=;k2<;k2++) map[k1][k2]=tempmap[k1][k2];
}
}
} int main()
{
ans=INF;
for (int i=;i<;i++)
{
char c;
for (int j=;j<;j++)
{
scanf("%c",&c);
if (c=='w') map[i][j]=; else map[i][j]=;
}
getchar();
}
recurrence(,);
if (ans!=INF) cout<<ans<<endl;else cout<<"Impossible"<<endl;
}
【模拟+递归+位运算】POJ1753-Flip Game的更多相关文章
- [CSP-S模拟测试]:位运算(数学)
题目传送门(内部题72) 输入格式 输入文件$bit.in$ 每个输入文件包含$T$组测试数据.输入文件的第一行为一个整数$T$,表示数据组数.接下来$T$行,每行表示一组测试数据每组测试数据包括三个 ...
- Winner Winner【模拟、位运算】
Winner Winner 题目链接(点击) 题目描述 The FZU Code Carnival is a programming competetion hosted by the ACM-ICP ...
- UVa 818Cutting Chains (暴力dfs+位运算+二进制法)
题意:有 n 个圆环,其中有一些已经扣在一起了,现在要打开尽量少的环,使所有的环可以组成一条链. 析:刚开始看的时候,确实是不会啊....现在有点思路,但是还是差一点,方法也不够好,最后还是参考了网上 ...
- 为什么位运算可以实现加法(1、 不考虑进位的情况下位运算符中的异或^可以表示+号)(2、 位运算符中的与运算符&和左移运算符<<可以模拟加法中的进位)(3、位运算不仅可以做加法,还可以做其它的乘法减法等:计算机本质是二进制运算)
为什么位运算可以实现加法(1. 不考虑进位的情况下位运算符中的异或^可以表示+号)(2. 位运算符中的与运算符&和左移运算符<<可以模拟加法中的进位)(3.位运算不仅可以做加法,还 ...
- 神奇的Noip模拟试题 T3 科技节 位运算
3 科技节 (scifest.pas/.c/.cpp) [问题描述] 一年一度的科技节即将到来.同学们报名各项活动的名单交到了方克顺校长那,结果校长一看皱了眉头:这帮学生热情竟然如此高涨,每个人都报那 ...
- 【NOIP模拟题】“与”(位运算)
因为是与运算,所以我们可以贪心地每次找最高位的,将他们加入到新的序列中,然后每一次在这个新的序列继续找下一个位. 然后最后序列中任意两个的与运算的值都是一样的且是最大的. #include <c ...
- 模拟赛T5 : domino ——深搜+剪枝+位运算优化
这道题涉及的知识点有点多... 所以还是比较有意思的. domino 描述 迈克生日那天收到一张 N*N 的表格(1 ≤ N ≤ 2000),每个格子里有一个非 负整数(整数范围 0~1000),迈克 ...
- poj1753,Flip Game,ArrayDeque<Node>
Flip Game Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 30449 Accepted: 13232 Descr ...
- js中的位运算
按位运算符是把操作数看作一系列单独的位,而不是一个数字值.所以在这之前,不得不提到什么是"位": 数值或字符在内存内都是被存储为0和 1的序列,每个0和1被称之为1个位,比如说10 ...
随机推荐
- linux下 vi中[noeol]以及出现 feff 的问题
"uptime.py" [noeol] 69L, 2311C"system/uptime.py" 69L, 2312C 'noeol' 就是 'no end-o ...
- hdu 1003 Max Sum (DP)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1003 Max Sum Time Limit: 2000/1000 MS (Java/Others) ...
- python中正则用法举例
一.根据正则表达式替换字符串 import re text='abc123' text=re.sub(r'\d','-',text) print(text) 输出:abc---将每个数字替换为-,如果 ...
- Port-knocking 简单教程
0. "port knocking" 如字面意思,类似'敲门',只是这里敲的是'端口',而且需要按照顺序'敲'端口.如果敲击规则匹配,则可以让防火墙实时更改策略.从而达到开关防火墙 ...
- ImportError: libQtTest.so.4: cannot open shared
错误: import cv2 File , in <module> from .cv2 import * ImportError: libQtTest.so.: cannot open s ...
- python模块(requests,logging)
一.requests Requests 是使用 Apache2 Licensed 许可证的 基于Python开发的HTTP 库,其在Python内置模块的基础上进行了高度的封装,从而使得Pythone ...
- kernel defconfig
Some defconfig files are placed on below path. Only one *_defconfig can be selected. android/kernel/ ...
- 步骤一:下载jdk并安装和配置java环境变量
1.下载JDk地址: http://download.eclipse.org/oomph/jre/?vm=1_1_7_0_64_0 2.进入下载页面(下载的是jdk7),点击:Oracle JDK1. ...
- P2885
2885 code[class*="language-"] { padding: .1em; border-radius: .3em; white-space: normal; b ...
- LockSupport学习
LockSupport工具类定义了一组的公共静态方法,这些方法提供了最基本的线程阻塞和唤醒功能.Java锁和同步器框架的核心工具类AQS:AbstractQueueSynchronizer,就是通过调 ...