题目大意:
就是现在有一个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; }