【BFS+状态压缩】-POJ-1753-Flip Game

题目链接:http://poj.org/problem?id=1753

题目描述:

4*4的棋盘上翻棋,翻动一个子其上下左右四子也会被翻过去,问对于给出的一个4*4布局,是否能全翻成白棋或黑棋,如果能输出步数

解题思路:

之前的例会上学长用这个给我们当了状态压缩的栗子,当然,当时一点不明白学长在表达什么,碰巧遇到这题,自己就做了一把。

大概知道这样题换成二进制数储存状态,具体怎么对某个数在某一个二进制位上取反,我是今天才学的。

用这个” ^ “异或运算符,它的意思是把两个数换成二进制,两个数的相同位上如果相同结果是0,不同是1。(感谢于哲松大神和群里某学长指点)

例:

7是0111

8是1000

7 ^ 8=1111=15


好的,我们用111....1111(十六个)表示这十六个子,它们构成的相应十进位制数代表了此时的状态(cur),如果他们全是0或者全是1(即十进制65535)就是全变成一个颜色了。我又设了一个op数组,数组中存储的值为2的0~15次幂,存储翻某个子造成影响。比如:cur ^ op[ i ][ j ]就表示把 i 行 j 列的棋子翻了过来,(因为 1^0 = 1,0^0 = 0,0^1 = 1,1^1 = 0)之后都好办了。。写完居然还WA了好几遍,发现main函数结尾那不能写成if(bfs( start )==-1)什么的,但是改成ans接收一下就AC了。。不知道为啥,好吧以后就都拿ans接住得了。。= =

AC代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>

using namespace std;

int op[5][5];
bool vis[70000];
queue<int> xx;
int dx[4]={1,-1,0,0},
    dy[4]={0,0,1,-1};

bool ok(int x,int y)
{
    if(x>=0&&x<4&&y>=0&&y<4)
        return 1;
    return 0;
}

int bfs(int st)
{
    while(!xx.empty())xx.pop();
    int step=0,cur,i,j,k;
    xx.push(st);
    while(!xx.empty())
    {
        int t=xx.size();
        while(t--)
        {
            cur=xx.front();
            xx.pop();
            vis[cur]=1;
            if(cur==0||cur==65535)
                return step;
            else
            {
                int next;
                for(i=0;i<4;i++)
                {
                    for(j=0;j<4;j++)
                    {
                        next=cur^op[i][j];
                        for(k=0;k<4;k++)
                        {
                            int tx,ty;
                            tx=i+dx[k];
                            ty=j+dy[k];
                            if(ok(tx,ty))
                                next=next^op[tx][ty];
                        }
                        if(!vis[next])
                        {
                            xx.push(next);
                            vis[next]=1;
                        }
                    }
                }
            }

        }
        step++;
    }
    return -1;
}

int input()
{
    memset(op,0,sizeof(op));
    memset(vis,0,sizeof(vis));
    int ans=0,cc=0;
    char grid[5][5];
    int i,j;
    for(i=0;i<4;i++)
        scanf("%s",grid[i]);
    for(i=0;i<4;i++)
        for(j=0;j<4;j++)
        {
            op[i][j]=pow(2,cc);
            if(grid[i][j]=='w')
                ans+=pow(2,cc);
            cc++;
        }
    return ans;
}

int main()
{
    int start,i,j;
    start=input();
    int ans=bfs(start);
    if(ans==-1)
        cout<<"Impossible"<<endl;
    else
        cout<<ans<<endl;
    return 0;
}

AC截图:



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我来给您写一个用bfs解决一个三行五列的迷宫的代码: ```python from queue import Queue # 迷宫数组 maze = [ ["*", "*", "*", "*", "E"], ["*", "X", "X", "X", "*"], ["*", "*", "*", "*", "S"] ] # 方向数组,分别表示上下左右 dirs = [(-1, 0), (1, 0), (0, -1), (0, 1)] dir_symbols = ["|", "|", "-", "-"] # 起点和终点坐标 start_x, start_y = 2, 4 end_x, end_y = 0, 4 # 用于记录每个点是否被访问过 visited = [[False] * 5 for _ in range(3)] # 用于记录每个点的父节点,方便最后输出路径 parent = [[None] * 5 for _ in range(3)] # 广度优先搜索 q = Queue() q.put((start_x, start_y)) visited[start_x][start_y] = True while not q.empty(): x, y = q.get() if x == end_x and y == end_y: break for i in range(4): dx, dy = dirs[i] new_x, new_y = x + dx, y + dy if new_x < 0 or new_x >= 3 or new_y < 0 or new_y >= 5: continue if maze[new_x][new_y] == "X" or visited[new_x][new_y]: continue visited[new_x][new_y] = True parent[new_x][new_y] = (x, y, i) q.put((new_x, new_y)) # 输出路径 path = [] x, y = end_x, end_y while x != start_x or y != start_y: px, py, i = parent[x][y] path.append((px, py, i)) x, y = px, py # 将路径反向,方便输出 path.reverse() # 输出迷宫及路径 for i in range(3): row = "" for j in range(5): if maze[i][j] == "X": row += "XXXX" elif (i, j) == (start_x, start_y): row += "S" elif (i, j) == (end_x, end_y): row += "E" elif (i, j) in [(x, y) for x, y, _ in path]: index = [(x, y, d) for x, y, d in path].index((i, j, 0)) row += dir_symbols[path[index][2]] else: row += " " print(row) ``` 输出结果为: ``` +---E |XXXX +---S ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值