题目大意:
就是现在有一个n*m的棋盘,1 <= n , m <= 15, 棋盘上你有一个棋子就是国王,用 * 表示, . 表示空的格子, 然后B代表敌方的象,K代表敌方的马,R代表敌方的车
现在走的规则是国王每次可以走到自己周围的8个格子(水平,竖直或者对角线的方向), 象可以向对角线方向走任意格,车可以竖直或者水平方向走任意格,马可以从(x, y)位置走到(x + 1, y + 2), (x - 1, y + 2), (x - 1, y - 2), (x + 1, y - 2), (x +2, y - 1), (x + 2, y + 1), (x - 2, y + 1), (x - 2, y - 1)这8个位置
现在要求你操作国王,在不走到任何能被当前的敌方棋子吃掉的格子的情况下,逐个吃掉敌方的棋子至少需要走的步数,这里由于程序bug所以在你操作国王时,你走一步后敌方棋子都不会移动
大致思路:
首先这道题很明显可以考虑用到BFS, 这样就需要考虑每个格子能否走到下一个格子
由于本题中整个棋盘上的棋子数量不会超过15,可以用状态压缩的思想来判断当前这个格子能否走
用yes[ x ][ y ][ p ]表示对于坐标为 x, y 的点,走上去需要满足状态 p, p的二进制的每一位代表是否需要吃掉对应编号的棋子(比如 二进制数 101代表需要吃点棋子1和3才能走上位置(x, y)
那么在BFS的时候,判断周围的位置的yes数组值来决定能否进入
对于搜索的时候用vis[ x ][ y ][ p ] 记录进入位置 (x, y)且状态为 p 的情况已经访问过,不用继续加入队列访问
注意处理时出现的棋子相互阻挡前进的情况
Result : Accepted Memory : 85118 KB Time : 280 ms
/*
* Author: Gatevin
* Created Time: 2014/9/2 14:38:56
* File Name: I.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define x first
#define y second
#define mp(a, b) make_pair(a, b)
#define clr(x) memset(x, 0, sizeof(x));
queue <pair<pair<int, int>, int> > q;
int step[16][16][1 << 16];//走到(x, y)且状态为p的步数
bool vis[16][16][1 << 16];//记忆化
int yes[16][16];//进入位置(x, y)需要满足的状态
char maz[16][16];
int cnt;//敌方棋子数量
map <pair<int, int>, int> M;//敌方位于位置(x, y)的棋子的编号
int n,m;
int sx, sy;//起点坐标
int dx[] = {1, 1, 1, 0, 0, -1, -1, -1};//国王走8个方向
int dy[] = {1, 0, -1, 1, -1, 1, 0, -1};
void bfs()
{
q.push(mp(mp(sx, sy), 0));
vis[sx][sy][0] = 1;
while(!q.empty())
{
for(int i = 0; i < 8; i++)
{
int tx = q.front().x.x + dx[i];
int ty = q.front().x.y + dy[i];
int tp = q.front().y;
if(tx >= 1 && tx <= n && ty >= 1 && ty <= m && ((tp & yes[tx][ty]) == yes[tx][ty]) && !vis[tx][ty][tp])
{
vis[tx][ty][tp] = 1;//上一状态的终止
if(maz[tx][ty] == 'K' || maz[tx][ty] == 'B' || maz[tx][ty] == 'R')
{
tp = tp | (1 << M[mp(tx, ty)]);//杀死了敌方棋子,状态更新
}
vis[tx][ty][tp] = 1;//下一状态的开始
step[tx][ty][tp] = step[q.front().x.x][q.front().x.y][q.front().y] + 1;
q.push(mp(mp(tx, ty), tp));
}
}
q.pop();
}
int answer = 0x7fffffff;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
if(maz[i][j] == 'R' || maz[i][j] == 'B' || maz[i][j] == 'K')
{
if(vis[i][j][(1 << cnt) - 1])//杀死敌方所有棋子的状态
{
answer = min(answer, step[i][j][(1 << cnt) - 1]);
}
}
}
}
if(answer == 0x7fffffff)
{
printf("-1\n");
}
else
{
printf("%d\n", answer);
}
return;
}
void flagR(int nx, int ny)//车
{
int i = nx - 1;
while(i >= 1)
{
if(maz[i][ny] != '.')
{
yes[i][ny] += (1 << M[mp(nx, ny)]);
break;
}
else
{
yes[i][ny] += (1 << M[mp(nx, ny)]);
i--;
}
}
i = nx + 1;
while(i <= n)
{
if(maz[i][ny] != '.')
{
yes[i][ny] += (1 << M[mp(nx, ny)]);
break;
}
else
{
yes[i][ny] += (1 << M[mp(nx, ny)]);
i++;
}
}
int j = ny - 1;
while(j >= 1)
{
if(maz[nx][j] != '.')
{
yes[nx][j] += (1 << M[mp(nx, ny)]);
break;
}
else
{
yes[nx][j] += (1 << M[mp(nx, ny)]);
j--;
}
}
j = ny + 1;
while(j <= m)
{
if(maz[nx][j] != '.')
{
yes[nx][j] += (1 << M[mp(nx, ny)]);
break;
}
else
{
yes[nx][j] += (1 << M[mp(nx, ny)]);
j++;
}
}
return;
}
void flagB(int nx, int ny)
{
int d1[] = {1, 1, -1, -1};//象走四个方向
int d2[] = {1, -1, 1, -1};
for(int i = 0; i < 4; i++)
{
int tx = d1[i] + nx;
int ty = d2[i] + ny;
while(tx >= 1 && tx <= n && ty >= 1 && ty <= m)
{
if(maz[tx][ty] != '.')
{
yes[tx][ty] += (1 << M[mp(nx, ny)]);
break;
}
else
{
yes[tx][ty] += (1 << M[mp(nx, ny)]);
tx += d1[i];
ty += d2[i];
}
}
}
return;
}
void flagK(int nx, int ny)//马
{
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
if((abs(i - nx) == 1 && abs(j - ny) == 2) || (abs(i - nx) == 2 && abs(j - ny) == 1))
{
yes[i][j] += (1 << M[mp(nx, ny)]);
}
}
}
return;
}
int main()
{
clr(yes);
clr(vis);
clr(step);
cnt = 0;
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++)
{
getchar();
for(int j = 1; j <= m; j++)
{
scanf("%c", &maz[i][j]);
if(maz[i][j] == '*')
{
sx = i; sy = j;
}
if(maz[i][j] == 'R' || maz[i][j] == 'K' || maz[i][j] == 'B') M[mp(i, j)] = cnt++;
}
}
if(cnt == 0)//无敌方棋子
{
printf("0\n");
return 0;
}
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
switch(maz[i][j])//处理各个格子进入需要的状态
{
case 'R' : flagR(i, j); break;
case 'B' : flagB(i, j); break;
case 'K' : flagK(i, j); break;
}
}
}
bfs();
return 0;
}