POJ 1753 位运算+枚举
题意:
给出4*4的棋盘,只有黑棋和白棋,问你最少几步可以使棋子的颜色一样。
游戏规则是:如果翻动一个棋子,则该棋子上下左右的棋子也会翻一面,棋子正反面颜色相反。
思路:
都是暴搜枚举。
第一种方法:暴力dfs枚举
棋子只有最多翻一次,因为翻两次后结果和不翻是一样的,所以整个棋盘最多翻16次。
用step代表翻转的次数,当翻转了step次时,就看一下整个棋盘是否是清一色的。
当棋盘是清一色的时候就直接输出step,得到的就是最少翻转次数使棋盘清一色。
第二种方法:利用位运算来优化
因为棋子不是白就是黑,所以可以用0和1来表示。
然后为每一个棋子编号,并计算出该棋子若翻转会影响到的棋子的位置,可以把它们都看成是二进制的。
例如 棋子位置是 第二行第二列 则翻转该棋子会影响到的棋子位置是
0 0 0 0 0 1 0 0
0 1 0 0 1 0 1 0
0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0
二进制表示 0000 0100 0000 0000 0100 1010 0100 0000
当计算最小值时可以预处理一下,即计算出由全白到该方案最少需要步数以及全黑到该方案需要的最少步数。
然后每一种方案都可以通过枚举 dp[j] = min(dp[j], dp[i]+1)来得到,dp[i]表示左上的状态,dp[j]表示右上的状态。
j = 影响的棋子位置^i
再优化之:其实,所以用dp[(1<<16-1)^i]得到的状态j即是状态i到全黑的最少步数, 这样就可以减少一个数组的开销了。
第三种方法:利用棋子翻转的奇偶次数
预处理时计算出改变该棋子会影响的棋子位置
然后得到棋盘状态的二进制形式记做p
然后枚举翻棋子的情况,总共有2^16-1种,看一看如果翻这些牌并且改变了相应受影响位置的牌棋盘后会不会变成清一色
并记录最少的步数

Tips:
位运算的优先级比较小,所以应该st应该= (1<<16)-1,而不是1<<16-1
Code:
#include <stdio.h>
#include <cstring> int dir[][] = {, , -, , , , , , , -}; bool G[][] = {false};
bool flag;
int step;
void flip(int r, int c)
{
for (int i = ; i < ; ++i) {
int rr = dir[i][]+r, cc = dir[i][]+c;
G[rr][cc] = !G[rr][cc];
}
} bool check()
{
for (int i = ; i <= ; ++i)
for (int j = ; j <= ; ++j)
if (G[i][j] != G[][]) return false;
return true;
} void dfs(int x, int y, int depth)
{
if (depth == step) {
flag = check();
return;
}
if (flag || y == ) return; flip(x, y);
if (x < )
dfs(x+, y, depth+);
else dfs(, y+, depth+); flip(x, y);
if (x < )
dfs(x+, y, depth);
else dfs(, y+, depth);
} int main()
{
//freopen("in.txt", "r", stdin);
char c;
for (int i = ; i <= ; ++i) {
for (int j = ; j <= ; ++j) {
scanf("%c", &c);
if (c == 'w') G[i][j] = true;
else G[i][j] = false;
}
getchar();
}
for (step = ; step <= ; ++step) {
dfs(, , );
if (flag) break;
}
if (flag) printf("%d\n", step);
else puts("Impossible");
return ;
}
第一种方法:暴力dfs+枚举
#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
#define INF 0x1f1f1f1f int dir[][] = {, , , , , , , -, -, };
int eff[];
int dp[<<|];
const int st = (<<)-; bool check(int x, int y)
{
return x >= && x < && y >= && y < ;
} void init()
{
int tot = ;
for (int i = ; i < ; ++i) {
for (int j = ; j < ; ++j) {
int sta = ;
for (int k = ; k < ; ++k) {
int x = i+dir[k][], y = j+dir[k][];
if (check(x, y)) sta |= (<<(x*+y));///!!!
}
eff[tot++] = sta;
}
}
} void bfs()
{
for (int i = ; i <= st; ++i) {
if (dp[i] == INF) continue; ///!!!
for (int j = ; j < ; ++j) {
int sta = i^eff[j];
dp[sta] = min(dp[sta], dp[i]+);
}
}
} int main()
{
//printf("__%d\n", st);
// freopen("in.txt", "r", stdin);
memset(dp, INF, sizeof(dp));
dp[] = ;
init();
bfs();
char c[];
int p = ;
for (int i = ; i < ; ++i) {
scanf("%s", c);
for (int j = ; j < ; ++j) {
if (c[j] == 'w') p ^= (<<(i*+j));
}
}
if (dp[p] == INF && dp[p^st] == INF) puts("Impossible");
else printf("%d\n", min(dp[p], dp[p^st]));
return ;
}
第二种方法:利用位运算存状态,并预处理
#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std; const int INF = 0x1f1f1f1f;
const int st = (<<)-;
int dir[][] = {, , , , , , , -, -, };
int eff[]; bool check(int x, int y)
{
return x >= && x < && y >= && y < ;
} void init()
{
int tot = ;
for (int i = ; i < ; ++i) {
for (int j = ; j < ; ++j) {
int sta = ;
for (int k = ; k < ; ++k) {
int x = i+dir[k][], y = j+dir[k][];
if (check(x, y)) sta |= <<(*x+y);
}
eff[tot++] = sta;
}
}
} int main()
{
//freopen("in.txt", "r", stdin);
init();
int ans = INF;
char c[];
int p = ;
for (int i = ; i < ; ++i) {
scanf("%s", c);
for (int j = ; j < ; ++j) {
if (c[j] == 'b') p |= <<(i*+j);
}
}
for (int i = ; i <= st; ++i) {
int sum = ;
int pp = p;
for (int j = ; j < ; ++j) {
if ((<<j)&i) {
sum++;
pp ^= eff[j];///!!!
}
}
if (pp == || pp == st) ans = min(ans, sum);
}
if (ans == INF) puts("Impossible");
else printf("%d\n", ans);
return ;
}
第三种方法:利用枚举翻哪些牌
链接:http://poj.org/problem?id=1753
POJ 1753 位运算+枚举的更多相关文章
- 枚举进行位运算 枚举组合z
枚举进行位运算--枚举组合 public enum MyEnum { MyEnum1 = , //0x1 MyEnum2 = << , //0x2 MyEnum3 = << , ...
- POJ 1753. Flip Game 枚举or爆搜+位压缩,或者高斯消元法
Flip Game Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 37427 Accepted: 16288 Descr ...
- 在C#中对枚举进行位运算--枚举组合
由于枚举的基础类型类型为基本的数值类型,支持位运算,因此可以使用一个值表示多个枚举的组合,在定义枚举时需要指定枚举数为2的幂指数方便进行位运算,即枚举数为1,2,4,8…,或1,1<<1, ...
- POJ 3220 位运算+搜索
转载自:http://blog.csdn.net/lyhypacm/article/details/5813634 DES:相邻的两盏灯状态可以互换,给出初始状态.询问是否能在三步之内到达.如果能的话 ...
- poj 1222 EXTENDED LIGHTS OUT(位运算+枚举)
http://poj.org/problem?id=1222 题意:给一个确定的5*6放入矩阵.每一个格子都有一个开关和一盏灯,0表示灯没亮,1表示灯亮着.让你输出一个5*6的矩阵ans[i][j], ...
- POJ 2965 The Pilots Brothers' refrigerator 位运算枚举
The Pilots Brothers' refrigerator Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 151 ...
- poj 1753 Flip Game 枚举(bfs+状态压缩)
题目:http://poj.org/problem?id=1753 因为粗心错了好多次……,尤其是把1<<15当成了65535: 参考博客:http://www.cnblogs.com/k ...
- hdu 1882 Strange Billboard(位运算+枚举)
http://acm.hdu.edu.cn/showproblem.php?pid=1882 感觉非常不错的一道题. 给一个n*m(1<=n,m<=16)的矩阵,每一个格子都有黑白两面,当 ...
- POJ1222熄灯问题【位运算+枚举】
EXTENDED LIGHTS OUT Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 14231 Accepted: 8 ...
随机推荐
- Maven 实现Struts2注解配置步骤详解
1,pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www ...
- php数据库操作类
config.db.php <?php $db_config["hostname"] = "localhost"; //服务器地址 $db_config[ ...
- MTU & MSS 详解记录(转)
先学习理解一下帧的封装格式: 需要注意的是,区别两种帧封装格式:802标准帧和以太网帧 1,在802标准定义的帧格式中,长度字段是指它后续数据的字节长度,但不包括C R C检验 ...
- Transformations 方块转换
题目是中文题,就不做什么解释了,纯模拟题,主要要搞清楚这几种装换方式下标的变化: 第一种:顺时针旋转90度: c[j][n-i+1]=a[i][j]; 第二种:旋转180度: c[n-i+1][n-j ...
- Mfc资源消息的响应机制
Mfc消息的响应机制 Mfc中有很多资源,如图标资源,菜单资源,工具栏资源等等:那么,资源是如何进行消息响应和消息映射的呢? 它们的流程是: 某种资源——对应的ID号——消息映射——响应函数的声明与实 ...
- javascript (十) 变量
变量必须以字母开头 变量也能以 $ 和 _ 符号开头(不过我们不推荐这么做) 变量名称对大小写敏感(y 和 Y 是不同的变量) 声明(创建) JavaScript 变量 在 JavaScript 中创 ...
- 浅谈mapreduce程序部署
尽管我们在虚拟机client上能非常快通过shell命令,进行运行一些已经封装好实例程序,可是在应用中还是是自己敲代码,然后部署到server中去,以下,我通过程序进行浅谈一个程序的部署过程. 在启动 ...
- C# Http以文件的形式上传文件
以下的是上传的方法: // <summary> /// 将本地文件上传到指定的服务器(HttpWebRequest方法) /// </summary> /// <para ...
- Qt 4.7.4 完美动态编译发布动态调试,以及静态编译发布
首先是准备工作,去QT主页下载独立的QT类库安装包以及完整QT SDK安装包,还有QT Creator for windows 版 下载地址:http://qt.nokia.com/downloads ...
- Java Thread.join()详解(转)
(1)join方法是可以中断的(2)在线程joiner在另一个线程t上调用t.join(),线程joiner将被挂起,直到线程t结束(即t.isAlive()返回为false)才恢复 package ...