SGU536 Berland Chess bfs+状态压缩

题意:给定一个n*m的国际象棋棋盘。共有5种字符,'.'表示空,'*'表示白色王,‘K’表示黑色马,‘B’表示黑色象,‘R’表示黑色车。白色只有唯一一个棋子——王,黑色最多不超过15。现在黑色防出现问题,不能走步,但会吃掉出现在棋子路线上的白色棋子。问最少多少步,白色王可以把黑色全部吃完。若吃不完就输出-1.

题解:将黑色棋子保存到数组中,记录为0~t,令i为黑色棋子状态。i转换成二进制后,第k位为0表示第k个棋子已经被吃掉,为1表示未被吃掉,所以0<=i<=(1<<t)。从而map[i][j][k]表示在i状态下,白色王能否进入位置(j,k)。列出所有状态下的地图。然后就是BFS了,当搜到黑色棋子时转换状态,直到黑色全吃完或者队列为空。

注意,当吃完一个黑色棋子后,可能白色王就处在了其他黑色棋子的攻击范围;地图用BOOL型可以减少占用空间。


代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
const int maxn=15;
const int INF=1e8;
int t;
struct node{
    int x,y,num,key;
    char ch;
}e[maxn];//存黑色棋子
bool map[1<<maxn][maxn][maxn];//dp[i][j][k],表示i状态下,(j,k)位置是否可走;i为状态压缩
int vis[maxn][maxn];
char a[maxn][maxn];
int n,m;
int dir[8][2]={{-2,-1},{-2,1},{-1,-2},{-1,2},{1,-2},{1,2},{2,-1},{2,1}};//马走的方式
int dir2[8][2]={{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};//王走的方式



int bfs(int x1,int y1,int key)//广搜
{
    /*printf("key:%d\n",key);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
            printf("%d",map[key][i][j]);
        printf("\n");
    }*/
    node f,g;
    int i,xx,yy;
    queue<node>q;
    memset(vis,-1,sizeof(vis));
    f.x=x1;f.y=y1;f.num=0;f.key=key;
    for(i=0;i<t;i++)
        vis[e[i].x][e[i].y]=i;
    q.push(f);
    while(!q.empty())
    {
        f=q.front();
        //printf("%d %d %d %d\n",f.x,f.y,f.num,f.key);
        q.pop();
        for(i=0;i<8;i++)
        {
            xx=f.x+dir2[i][0];yy=f.y+dir2[i][1];key=f.key;
            if(xx<0||yy<0||xx>=n||yy>=m||map[key][xx][yy])continue;
            if(vis[xx][yy]!=-1&&((1<<vis[xx][yy])&f.key))
            {
                key-=(1<<vis[xx][yy]);
                if(key==0)return f.num+1;//全吃完输出结果
                if(map[key][xx][yy])continue;//吃完后背其他棋子吃的情况
            }
            map[key][xx][yy]=true;

            g.x=xx;g.y=yy;g.num=f.num+1,g.key=key;
            q.push(g);
        }
    }
    return INF;
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int i,j,k,x,y,xx,yy;
        t=0;
        memset(map,false,sizeof(map));
        for(i=0;i<n;i++)
            scanf("%s",a[i]);
        for(i=0;i<n;i++)
        {
            for(j=0;j<m;j++)
            {
                if(a[i][j]=='*'){x=i;y=j;}
                else if(a[i][j]!='.')
                {
                    e[t].x=i;
                    e[t].y=j;
                    e[t++].ch=a[i][j];
                }
            }
        }
        if(t==0){printf("0\n");continue;}//特判
        //制作地图
        int flag,c[4];
        for(i=1;i<(1<<maxn);i++)//i为状态,化成二进制,第k位为0表示第k个棋子已经被吃,否则存在。
        {
            memset(vis,0,sizeof(vis));
            for(j=0;j<t;j++)
            {
                if((1<<j)&i)
                {
                    vis[e[j].x][e[j].y]=true;
                    //map[i][e[j].x][e[j].y]=true;
                }
            }
            for(j=0;j<t;j++)
            {
                if((1<<j)&i)
                {
                    if(e[j].ch=='K')
                    {
                        for(k=0;k<8;k++)
                        {
                            xx=e[j].x+dir[k][0];
                            yy=e[j].y+dir[k][1];
                            if(xx<0||yy<0||xx>=n||yy>=m)continue;
                            map[i][xx][yy]=true;
                        }
                    }
                    else if(e[j].ch=='R')
                    {
                        k=1;
                        flag=c[0]=c[1]=c[2]=c[3]=1;
                        while(flag)
                        {
                            flag=0;
                            if(c[0]&&e[j].x+k<n)
                            {
                                if(vis[e[j].x+k][e[j].y])c[0]=0;
                                else{map[i][e[j].x+k][e[j].y]=true;flag=true;}

                            }
                            if(c[1]&&e[j].x-k>=0)
                            {
                                if(vis[e[j].x-k][e[j].y])c[1]=0;
                                else{map[i][e[j].x-k][e[j].y]=true;flag=true;}
                            }
                            if(c[2]&&e[j].y+k<m)
                            {
                                if(vis[e[j].x][e[j].y+k])c[2]=0;
                                else{map[i][e[j].x][e[j].y+k]=true;flag=true;}
                            }
                            if(c[3]&&e[j].y-k>=0)
                            {
                                if(vis[e[j].x][e[j].y-k])c[3]=0;
                                else{map[i][e[j].x][e[j].y-k]=true;flag=true;}
                            }
                            k++;
                        }
                    }
                    else if(e[j].ch=='B')
                    {
                        flag=c[0]=c[1]=c[2]=c[3]=1;
                        k=1;
                        while(flag)
                        {

                            flag=0;
                            if(c[0]&&e[j].x+k<n&&e[j].y+k<m)
                            {
                                if(vis[e[j].x+k][e[j].y+k])c[0]=0;
                                else{map[i][e[j].x+k][e[j].y+k]=true;flag=true;}
                            }
                            if(c[1]&&e[j].x+k<n&&e[j].y-k>=0)
                            {
                                if(vis[e[j].x+k][e[j].y-k])c[1]=0;
                                else{map[i][e[j].x+k][e[j].y-k]=true;flag=true;}
                            }
                            if(c[2]&&e[j].x-k>=0&&e[j].y+k<m)
                            {
                                if(vis[e[j].x-k][e[j].y+k])c[2]=0;
                                else{map[i][e[j].x-k][e[j].y+k]=true;flag=true;}
                            }
                            if(c[3]&&e[j].x-k>=0&&e[j].y-k>=0)
                            {
                                if(vis[e[j].x-k][e[j].y-k])c[3]=0;
                                else{map[i][e[j].x-k][e[j].y-k]=true;flag=true;}
                            }
                            k++;
                        }
                    }
                }
            }
        }
        int ans=bfs(x,y,(1<<t)-1);
        if(ans==INF)printf("-1\n");
        else printf("%d\n",ans);
    }
    return 0;
}

/*
15 15
...............
B..............
.K.............
..R............
...R...........
....R..........
.....R.........
......R........
.......R.......
........R......
.........R.....
...........R...
.............R.
...............
..............*
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值