状态压缩BFS poj1753 hdu5025 hdu1885

第一次接触 状态压缩类的题刚开始的话,完全没有思路也没有想到位运算,然后就各种gg,

废话不说了 直接上代码吧。

POJ 1753;

题意就是翻棋子,求使棋盘上的棋子都是白棋或者黑棋,因为只有16个格子int的范围还能容下1<<16所以就用一个数来表示当前的状态就可以了。这里有个小技巧,就是读入的时候一重循环16如果是黑色(这里以黑色为1,白色为0)开始的状态就j加1<<i。然后bfs就可以了,记得要判断边界条件。

补充一下位运算

如果要获得第i位的数据,判断((data&(0X1<<i))==0),若真,为0,假,为1;
如果要设置第i位为1,data=(data|(0X1<<i));
如果要设置第i位为0,data=(data&(~(0X1<<i)));
如果要将第i位取反,data=(data^(0X1<<i);
如果要取出一个数的最后一个1(lowbit):(data&(-data))         (这里利用的是负数取反加1实际上改变的是二进制最低位的1如果要获得第i位的数据,判断((data&(0X1<<i))==0),若真,为0,假,为1;
如果要设置第i位为1,data=(data|(0X1<<i));
如果要设置第i位为0,data=(data&(~(0X1<<i)));
如果要将第i位取反,data=(data^(0X1<<i);
如果要取出一个数的最后一个1(lowbit):(data&(-data))         (这里利用的是负数取反加1实际上改变的是二进制最低位的1这个性质

#include <iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
struct node
{
    int date;
    int step;
};
bool book[65536],flag=0;
int bfs(int st)
{
    memset(book,0,sizeof(book));
    struct node head,tail;
    head.date=st; head.step=0;
    book[st]=1;
    queue<node> que;
    que.push(head);
    while(!que.empty())
    {
        head=que.front();
        que.pop();
        if(head.date==0||head.date==65535)
        {
            printf("%d\n",head.step);
            return 1;
        }
        for(int i=0;i<16;i++)
        {
            tail.date=head.date^(1<<i);
            if(i%4)
            {
                tail.date=tail.date^(1<<(i-1));
            }
            if(i>3)
            {
                tail.date=tail.date^(1<<(i-4));
            }
            if(i<12)
            {
                tail.date=tail.date^(1<<(i+4));
            }
            if((i+1)%4)
            {
                tail.date=tail.date^(1<<(i+1));
            }
            if(!book[tail.date])
            {
                tail.step=head.step+1;
                book[tail.date]=1;
                que.push(tail);
            }
        }
    }
    return 0;
}
int main()
{
    int st=0;
    for(int i=0;i<16;i++)
    {
        char c;
        scanf(" %c",&c);
        if(c=='b')
        {
            st+=1<<i;
        }
    }
     flag=bfs(st);
    if(flag==0) printf("Impossible\n");
    return 0;
}


hdu 1885
和上道题一样就是用位运算保存 ,但是自己错了好多次。
#include <iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
char map[120][120];
struct node
{
    int x,y,snake,step,keys;
    bool friend operator <(const node &a,const node & b)
    {
        return a.step>b.step;
    }
};
bool vis[120][120][10][(1<<5)+5];
int dir[4][2]={0,1,0,-1 ,1,0 ,-1,0};
int n,k;
int sx,sy,ex,ey;
int book[120][120];
bool check(int x,int y)
{
    if(x<=0||y<=0||x>n||y>n) return 0;
    return 1;
}
int bfs()
{
   struct node head,tail;
   head.x=sx;head.y=sy;head.step=0;head.keys=0;head.snake=0;
   vis[sx][sy][0][0]=1;
   priority_queue<node> que;
   que.push(head);
   while(!que.empty())
   {
      head=que.top();
      que.pop();
      if(head.x==ex&&head.y==ey&&head.keys==k)
      {
          return head.step;
      }
      for(int i=0;i<4;i++)
      {
          tail.x=head.x+dir[i][0];
          tail.y=head.y+dir[i][1];
          tail.snake=head.snake;
          tail.step=head.step+1;
          tail.keys=head.keys;
          if(check(tail.x,tail.y)&&!vis[tail.x][tail.y][tail.keys][tail.snake]&&map[tail.x][tail.y]!='#')
          {
              int key=map[tail.x][tail.y]-'0';
              if(tail.keys+1==key)
              {
                 tail.keys+=1;
                 vis[tail.x][tail.y][tail.keys][tail.snake]=1;
                 que.push(tail);
              }
              else if(map[tail.x][tail.y]=='S')
              {
                 if(tail.snake&(1<<book[tail.x][tail.y]))
                 {
                     vis[tail.x][tail.y][tail.keys][tail.snake]=1;
                    que.push(tail);
                 }
                 else
                 {

                     tail.snake+=1<<book[tail.x][tail.y];
                     tail.step++;
                     vis[tail.x][tail.y][tail.keys][tail.snake]=1;
                     que.push(tail);
                 }
              }
              else
              {
                  vis[tail.x][tail.y][tail.keys][tail.snake]=1;
                  que.push(tail);
              }
          }
      }
   }
   return -1;
}
int main()
{
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        if(n==0&&k==0) break;
        memset(vis,0,sizeof(vis));
        int cnt=0,ans=-1;
        for(int i=1;i<=n;i++)
        {
          for(int j=1;j<=n;j++)
          {
            scanf(" %c",&map[i][j]);
            if(map[i][j]=='T') {ex=i;ey=j;}
            else if(map[i][j]=='K') {sx=i;sy=j;}
            else if(map[i][j]=='S') { book[i][j]=cnt++;}
          }
        }
        ans=bfs();
        if(ans!=-1) printf("%d\n",ans);
        else printf("impossible\n");
    }
    return 0;
}

hdu 5025
这道题就是孙哥。去救师傅。用个四位vis标记,这道题的keys比较好解决,如果他碰到钥匙必须在把前面的钥匙拿齐的情况下才能捡起这个钥匙,第二个条件是蛇因为只有五个蛇所以用cnt把每个蛇标记,还有如果已经把蛇打死就不需要再打了。还有一点就是如果碰到师傅,但没有拿齐钥匙也不能救师傅。。加上优先队列优化哈。
#include <iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
char map[120][120];
struct node
{
    int x,y,snake,step,keys;
    bool friend operator <(const node &a,const node & b)
    {
        return a.step>b.step;
    }
};
bool vis[120][120][10][(1<<5)+5];
int dir[4][2]={0,1,0,-1 ,1,0 ,-1,0};
int n,k;
int sx,sy,ex,ey;
int book[120][120];
bool check(int x,int y)
{
    if(x<=0||y<=0||x>n||y>n) return 0;
    return 1;
}
int bfs()
{
   struct node head,tail;
   head.x=sx;head.y=sy;head.step=0;head.keys=0;head.snake=0;
   vis[sx][sy][0][0]=1;
   priority_queue<node> que;
   que.push(head);
   while(!que.empty())
   {
      head=que.top();
      que.pop();
      if(head.x==ex&&head.y==ey&&head.keys==k)
      {
          return head.step;
      }
      for(int i=0;i<4;i++)
      {
          tail.x=head.x+dir[i][0];
          tail.y=head.y+dir[i][1];
          tail.snake=head.snake;
          tail.step=head.step+1;
          tail.keys=head.keys;
          if(check(tail.x,tail.y)&&!vis[tail.x][tail.y][tail.keys][tail.snake]&&map[tail.x][tail.y]!='#')
          {
              int key=map[tail.x][tail.y]-'0';
              if(tail.keys+1==key)
              {
                 tail.keys+=1;
                 vis[tail.x][tail.y][tail.keys][tail.snake]=1;
                 que.push(tail);
              }
              else if(map[tail.x][tail.y]=='S')
              {
                 if(tail.snake&(1<<book[tail.x][tail.y]))
                 {
                     vis[tail.x][tail.y][tail.keys][tail.snake]=1;
                    que.push(tail);
                 }
                 else
                 {

                     tail.snake+=1<<book[tail.x][tail.y];
                     tail.step++;
                     vis[tail.x][tail.y][tail.keys][tail.snake]=1;
                     que.push(tail);
                 }
              }
              else
              {
                  vis[tail.x][tail.y][tail.keys][tail.snake]=1;
                  que.push(tail);
              }
          }
      }
   }
   return -1;
}
int main()
{
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        if(n==0&&k==0) break;
        memset(vis,0,sizeof(vis));
        int cnt=0,ans=-1;
        for(int i=1;i<=n;i++)
        {
          for(int j=1;j<=n;j++)
          {
            scanf(" %c",&map[i][j]);
            if(map[i][j]=='T') {ex=i;ey=j;}
            else if(map[i][j]=='K') {sx=i;sy=j;}
            else if(map[i][j]=='S') { book[i][j]=cnt++;}
          }
        }
        ans=bfs();
        if(ans!=-1) printf("%d\n",ans);
        else printf("impossible\n");
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
POJ1753题目为"Flip Game",题目给出了一个4x4的棋盘,每个格子有黑色或白色,每次翻转一个格子会同时翻转它上下左右四个格子的颜色,目标是把整个棋盘都变为同一种颜色,求把棋盘变成同种颜色的最小步数。 解题思路: 一般关于棋盘变色的题目,可以考虑使用搜索来解决。对于POJ1753题目,可以使用广度优先搜索(BFS)来解决。 首先,对于每个格子,定义一个状态,0表示当前格子是白色,1表示当前格子是黑色。 然后,我们可以把棋盘抽象成一个长度为16的二进制数,将所有格子的状态按照从左往右,从上往下的顺序排列,就可以用一个16位的二进制数表示整个棋盘的状态。例如,一个棋盘状态为: 0101 1010 0101 1010 则按照从左往右,从上往下的顺序把所有格子的状态连接起来,即可得到该棋盘的状态为"0101101001011010"。 接着,我们可以使用队列来实现广度优先搜索。首先将初始状态加入队列中,然后对于队列中的每一个状态,我们都尝试将棋盘上的每个格子翻转一次,生成一个新状态,将新状态加入队列中。对于每一个新状态,我们也需要记录它是从哪个状态翻转得到的,以便在得到最终状态时能够输出路径。 在搜索过程中,我们需要维护每个状态离初始状态的步数,即将该状态转换为最终状态需要的最小步数。如果我们找到了最终状态,就可以输出答案,即最小步数。 代码实现:

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值