POJ 1753 位运算+枚举
2013-07-16 10:57
351 查看
题意:
给出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
再优化之:其实
第三种方法:利用枚举翻哪些牌
链接:http://poj.org/problem?id=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
再优化之:其实
#include <stdio.h> #include <cstring> #include <algorithm> using namespace std; const int INF = 0x1f1f1f1f; const int st = (1<<16)-1; int dir[5][2] = {0, 0, 0, 1, 1, 0, 0, -1, -1, 0}; int eff[16]; bool check(int x, int y) { return x >= 0 && x < 4 && y >= 0 && y < 4; } void init() { int tot = 0; for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { int sta = 0; for (int k = 0; k < 5; ++k) { int x = i+dir[k][0], y = j+dir[k][1]; if (check(x, y)) sta |= 1<<(4*x+y); } eff[tot++] = sta; } } } int main() { //freopen("in.txt", "r", stdin); init(); int ans = INF; char c[6]; int p = 0; for (int i = 0; i < 4; ++i) { scanf("%s", c); for (int j = 0; j < 4; ++j) { if (c[j] == 'b') p |= 1<<(i*4+j); } } for (int i = 0; i <= st; ++i) { int sum = 0; int pp = p; for (int j = 0; j < 16; ++j) { if ((1<<j)&i) { sum++; pp ^= eff[j];///!!! } } if (pp == 0 || pp == st) ans = min(ans, sum); } if (ans == INF) puts("Impossible"); else printf("%d\n", ans); return 0; }
第三种方法:利用枚举翻哪些牌
链接:http://poj.org/problem?id=1753
相关文章推荐
- [ACM] POJ 1753 Flip Game (枚举,BFS,位运算)
- poj 1753 、poj 2965 (枚举)(位运算)
- POJ 1753 Flip Game (枚举 + 位运算)
- POJ 1753 Flip Game (高斯消元 枚举自由变元求最小步数)
- 入门专题第一道基础题 POJ 1753 (枚举和深搜)
- POJ 1753 Flip Game(二进制枚举)
- poj 1753 Flip Game(bfs状态压缩 或 dfs枚举)
- POJ_1753(位运算)
- poj 1753 filp game 2015年暑假训练第一题 枚举
- POJ - 1753 Flip Game(枚举+反转)
- POJ 1753 Flip Game(高斯消元法,枚举自由变元)
- 【POJ】1753 - Flip Game(bfs,枚举)
- poj 1753 Flip Game——DFS(分类是枚举)
- POJ 1753 Flip Game (递归枚举)
- poj 1753||poj 2965 枚举+dfs
- Fliptile POJ - 3279 (状态压缩+枚举) && Flip Game POJ - 1753(状态压缩+bfs暴力)
- POJ 1753 Flip Game (枚举)
- POJ 1753 FLIP GAME——枚举深度的dfs
- poj 1753 flip[ 枚举 ]
- POJ1753 枚举