poj1753 bfs+奇偶性减枝//状压搜索

http://poj.org/problem?id=1753

题意:有个4*4的棋盘,上面摆着黑棋和白旗,b代表黑棋,w代表白棋,现在有一种操作,如果你想要改变某一个棋子的颜色,那么它周围(前后左右)棋子的颜色都会被改变(白变成黑,黑变成白),问你将所有棋子变成白色或者黑色最少的步数。

思路:

1、如果用一个4*4的数组存储每一种状态,不但存储空间很大,而且在穷举状态时也不方便记录。因为每一颗棋子都只有两种状态,所以可以用二进制0和1表示每一个棋子的状态,则棋盘的状态就可以用一个16位的整数唯一标识。而翻转的操作也可以通过通过位操作来完成。显然当棋盘状态id为0(全白)或65535(全黑)时,游戏结束。

2、对于棋盘的每一个状态,都有十六种操作,首先要判断这十六种操作之后是否有完成的情况,如果没有,则再对这十六种操作的结果分别再进行上述操作,显然这里就要用到队列来存储了。而且在翻转的过程中有可能会回到之前的某种状态,而这种重复的状态是不应该再次入队的,所以维护 Visit[i]数组来判断 id==i 的状态之前是否已经出现过,如果不是才将其入队。如果游戏无法完成,状态必定会形成循环,由于重复状态不会再次入队,所以最后的队列一定会是空队列。

3、由于0^1=1,1^1=0,所以翻转的操作可以通过异或操作来完成,而翻转的位置可以通过移位来确定。

AC代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
#include<queue>
using namespace std;

int change[16] =
{
    51200,58368,29184,12544,
    35968,20032,10016,4880,
    2248,1252,626,305,
    140,78,39,19
};
bool visit[65536];
struct Node
{
    int state;
    int step;
};
int bfs(int state)
{
    memset(visit,false,sizeof(visit));
    queue<Node>q;
    Node now,next;
    now.state=state;
    now.step=0;
    q.push(now);
    visit[state]=true;
    while(!q.empty())
    {
        now=q.front();
        q.pop();
        if(now.state==0 || now.state==0xffff)
            return now.step;
        for(int i=0; i<16; i++)
        {
            next.state = now.state^change[i];
            next.step = now.step+1;
            if(visit[next.state]) continue;
            if(next.state==0 || next.state==0xffff)
                return next.step;
            visit[next.state]=true;
            q.push(next);
        }
    }
    return -1;
}

int main()
{
    char str[4][5];
    int state,ans;
    while(scanf("%s",str[0])!=EOF)
    {
        for(int i=1; i<4; i++)
            scanf("%s",str[i]);
        state=0;
        for(int i=0; i<4; i++)
            for(int j=0; j<4; j++)
            {
                state<<=1;
                if(str[i][j]==‘b‘)
                    state+=1;
            }
        ans=bfs(state);
        if(ans==-1) puts("Impossible");
        else printf("%d\n",ans);
    }
    return 0;
}
时间: 2024-08-07 00:03:32

poj1753 bfs+奇偶性减枝//状压搜索的相关文章

poj1753:状压搜索

状压+打表+bfs即可.ccz大神扫一眼:异或...遂秒 ------------------------------------------------------------------------------------ #include<cstdio>#include<queue>#include<cstring>#include<iostream>#include<algorithm>using namespace std;#defin

HDU 5025 (BFS+记忆化状压搜索)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5025 题目大意: 迷宫中孙悟空救唐僧,可以走回头路.必须收集完钥匙,且必须按顺序收集.迷宫中还有蛇,杀蛇多耗时1,蛇杀完就没了.问最少耗时. 解题思路: 2014广州网赛的水题之一.当时没刷过BFS状压,结果悲剧了. 首先这题可以压钥匙,也可以压蛇,不过压钥匙内存岌岌可危,于是就压蛇吧. 设f[x][y][key][snake]为在(x,y)点,已经取得的钥匙key,以及杀蛇snake的状态. 对

HDU 5025 Saving Tang Monk(状压搜索)

钥匙是必须有序,蛇是不要求有序的.所以一个需要状压一个不用 因为时间计算和步数计算不同.所以要遍历整个空间,或者使用优先队列.优先时间短的. 风格就这样了. #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <queue> #define inf 0x3f3f3f3f #define maxn 110 using names

CH 2101 - 可达性统计 - [BFS拓扑排序+bitset状压]

题目链接:传送门 描述 给定一张N个点M条边的有向无环图,分别统计从每个点出发能够到达的点的数量.N,M≤30000. 输入格式 第一行两个整数N,M,接下来M行每行两个整数x,y,表示从x到y的一条有向边. 输出格式 共N行,表示每个点能够到达的点的数量. 样例输入 10 10 3 8 2 3 2 5 5 9 5 9 2 3 3 9 4 8 2 10 4 9 样例输出 1 6 3 3 2 1 1 1 1 1 题解: 首先,如果用 $f(x)$ 代表从点 $x$ 出发所能到达的所有点的集合,应有

HDU 1429 (BFS+记忆化状压搜索)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1429 题目大意:最短时间内出迷宫,可以走回头路,迷宫内有不同的门,对应不同的钥匙. 解题思路: 要是没有门和钥匙,而且不能走回头路,就是个简单粗暴的BFS. 有了门之后,就要状态压缩+记忆化搜索.不然这个图会搜死你. 本题的状态压缩基于一个事实:尽管可以走回头路,但是回头是有理由的,你要么开了门,要么拿了钥匙,使状态发生改变. 否则等于多绕了一步,浪费时间,应该及时剪枝. f[x][y][key]

UVA 1377 Ruler bfs+状压搜索

题目链接:点击打开链接 题意:给定n个刻度.下面是n个刻度. 要构造一个尺子使得上面的n个刻度能直接量出来. 且要满足尺子上的刻度线个数最少,最少的情况下尺子最短. 第一个刻度总为0 题目保证总是存在<7个刻度线的解. 思路: bfs,每次枚举新加一个刻度后,哪些可以直接量出来,用二进制表示,然后暴力搜 剪枝: 1.若加入一个新刻度后并不能多测量给定的n个刻度那么加入的刻度就无效(即加入前和加入后的状态相同) 2.尺子的长度若大于最大刻度则无效 import java.io.PrintWrite

icpc live archive6454(状压搜索)

https://icpcarchive.ecs.baylor.edu/external/64/6454.pdf 求最少的灯照亮所有.的区域,但不能照到#号区域,可以照到界限之外,每个.号上只能放一盏灯.灯照的区域为L形,灯在拐角处.大多数灯是这样没错,但有一盏灯比较特殊,可以是L的其他三种旋转体. 状态压缩搜索,状态为放置的灯的状态,(.)点最多只有15个,做好序号可以直接存进一个int型里. 代码(中间有一些比较繁琐): #include<iostream> #include<cstd

POJ 5025 Saving Tang Monk(状压搜索)

http://acm.hdu.edu.cn/showproblem.php?pid=5025 搜索题:注意蛇的状态(第一次路过要杀掉蛇花2s,第二次以后1s).状态为坐标 ,蛇 加钥匙最大值.用[坐标加拿到最高等级的钥匙]去重. 代码: #include<iostream> #include<queue> #include<map> #include<cstdio> #include<string> #include<cstring>

hdu1010 dfs+奇偶性减枝

Tempter of the Bone Problem Description The doggie found a bone in an ancient maze, which fascinated him a lot. However, when he picked it up, the maze began to shake, and the doggie could feel the ground sinking. He realized that the bone was a trap