您的位置:首页 > 其它

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

    

    再优化之:其实

#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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: