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 ...
随机推荐
- 王立平--PopupWindow
MainActivity.java <span style="font-size:14px;">package com.main; import android.app ...
- python3语法小记(二)列表 和 元组
列表(list): 列表就像一个线性容器,但是比C++的 lis t扩展多得多 列表里的元素可以是相同类型,也可以包含各种类型,比如列表里嵌套另一个列表 >>> L1 = [1,2, ...
- ASP.NET - 在类中如何使用 Server.MapPath
直接在类中使用 Server.MapPath 会出现错误,这是由于类中不能直接使用 System.Web.UI.Page 的非静态函数造成的.解决方法有两种: 方法一.为类增加继承 class CFo ...
- QNX系统-关于delay函数与sleep函数的区别
QNX是类unix系统.在c语言编程过程中,往往会用到delay或者sleep延时函数.两者之间在使用上有一定的区别!!! delay()是循环等待,该进程还在运行,占用处理器. sleep()不同, ...
- Android应用中使用百度地图API并加入标注(一)
网上一些资料这样的的内容已经过时了,这里是最新的内容,假设哪里不正确,请吐槽... 1)下载百度地图移动版API(Android)开发包 要在Android应用中使用百度地图API,就须要 ...
- 【源代码】基于Android和蓝牙的单片机温度採集系统
如需转载请标明出处:http://blog.csdn.net/itas109 QQ技术交流群:129518033 STC89C52单片机通过HC-06蓝牙模块与Android手机通信实例- 基于And ...
- blender资源
blender资源 只能发帖不能更改的百度贴吧贴. http://tieba.baidu.com/f?kw=blender blendercn youku视频专辑: http://i.youku.co ...
- Org-mode五分钟教程ZZZ - Kaka Abel的日志 - 网易博客
Org-mode五分钟教程ZZZ - Kaka Abel的日志 - 网易博客 Org-mode五分钟教程ZZZ
- linux ifconfig命令使用详解
Linux下网卡命名规律:eth0,eth1.第一块以太网卡,第二块.lo为环回接口,它的IP地址固定为127.0.0.1,掩码8位.它代表你的机器本身. 1.ifconfig是查看网卡的信息. if ...
- jQuery遍历函数
jQuery遍历函数包含了用于筛选.查找和串联元素的方法. .add():将元素加入到匹配元素的集合中. .andSelf():把堆栈中之前的元素集加入到当前集合中. .children():获得匹配 ...