由于数据规模不大,利用爆搜即可。第一次用位运算写的,但是转念一想应该用递归更加快,因为位运算没有剪枝啊(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的更多相关文章

  1. [CSP-S模拟测试]:位运算(数学)

    题目传送门(内部题72) 输入格式 输入文件$bit.in$ 每个输入文件包含$T$组测试数据.输入文件的第一行为一个整数$T$,表示数据组数.接下来$T$行,每行表示一组测试数据每组测试数据包括三个 ...

  2. Winner Winner【模拟、位运算】

    Winner Winner 题目链接(点击) 题目描述 The FZU Code Carnival is a programming competetion hosted by the ACM-ICP ...

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

    题意:有 n 个圆环,其中有一些已经扣在一起了,现在要打开尽量少的环,使所有的环可以组成一条链. 析:刚开始看的时候,确实是不会啊....现在有点思路,但是还是差一点,方法也不够好,最后还是参考了网上 ...

  4. 为什么位运算可以实现加法(1、 不考虑进位的情况下位运算符中的异或^可以表示+号)(2、 位运算符中的与运算符&和左移运算符<<可以模拟加法中的进位)(3、位运算不仅可以做加法,还可以做其它的乘法减法等:计算机本质是二进制运算)

    为什么位运算可以实现加法(1. 不考虑进位的情况下位运算符中的异或^可以表示+号)(2. 位运算符中的与运算符&和左移运算符<<可以模拟加法中的进位)(3.位运算不仅可以做加法,还 ...

  5. 神奇的Noip模拟试题 T3 科技节 位运算

    3 科技节 (scifest.pas/.c/.cpp) [问题描述] 一年一度的科技节即将到来.同学们报名各项活动的名单交到了方克顺校长那,结果校长一看皱了眉头:这帮学生热情竟然如此高涨,每个人都报那 ...

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

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

  7. 模拟赛T5 : domino ——深搜+剪枝+位运算优化

    这道题涉及的知识点有点多... 所以还是比较有意思的. domino 描述 迈克生日那天收到一张 N*N 的表格(1 ≤ N ≤ 2000),每个格子里有一个非 负整数(整数范围 0~1000),迈克 ...

  8. poj1753,Flip Game,ArrayDeque&lt;Node&gt;

    Flip Game Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 30449   Accepted: 13232 Descr ...

  9. js中的位运算

    按位运算符是把操作数看作一系列单独的位,而不是一个数字值.所以在这之前,不得不提到什么是"位": 数值或字符在内存内都是被存储为0和 1的序列,每个0和1被称之为1个位,比如说10 ...

随机推荐

  1. bzoj 1927 网络流

    首先我们可以知道这道题中每个点只能经过一次,那么我们引入附加源汇source,sink,那么我们可以将每个点拆成两个点,分别表示对于图中这个节点我们的进和出,那么我们可以连接(source,i,1,0 ...

  2. vs调试 配置IISExpress允许局域网内部访问

    内网可访问后,本机不能使用localhost   1.找到IISExpress的配置文件,位于 <文档>/IISExpress/config文件夹下,打开applicationhost.c ...

  3. js_一个简单的30分钟循环倒计时

    吐槽段: 需求的变更是千变万化的,至少在你说服和你打交道的那位谁谁谁之前. 创业公司就是这样,产品经理一个想法,就是改改改,管你改起来复杂不复杂,在他们眼里都是非常简单的. 今天的一个小改动需求,把活 ...

  4. Edgware Feign hystrix-dashboard

    相关依赖 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring ...

  5. perl中设置POST登录时的重定向

    默认地, perl提交post登录时是不会重定向的 要让它重定向, 可以用如下方法: my $cookie = HTTP::Cookies->new(); push @{$ua->requ ...

  6. vue-router 基础

    安装 NPM npm install vue-router 如果在一个模块化工程中使用它,必须要通过 Vue.use() 明确地安装路由功能: import Vue from 'vue' import ...

  7. Qt笔记——多线程

    这个例子是,点击开始按钮,数字累加,点击停止按钮,数字不动. 1,新建一个类,里面是子线程的内容 #ifndef MYTHREAD_H #define MYTHREAD_H #include < ...

  8. Spring学习(一)——Spring中的依赖注入简介

    [前面的话] Spring对我太重要了,做个关于web相关的项目都要使用Spring,每次去看Spring相关的知识,总是感觉一知半解,没有很好的系统去学习一下,现在抽点时间学习一下Spring.不知 ...

  9. git 命令小结

    一.git 版本管理 1.git log: 获取当前版本之前的所有操作 2.git log --pretty=oneline:获取当前版本的前三和后三个操作 3.git reflog :获取当前项目下 ...

  10. rpm包管理和源码包管理

    (1)软件类型 源码包 需要gcc编译 nginx-1.12.1.tar.gz 二进制包 已编译 mysql-community-common-5.7.12-1.el7.x86_64.rpm 常见的二 ...