Problem I. CollectingCoins
In a maze of r rows and ccolumns, your task is to collect as many coins as possible.
Each square is either your startpoint "S"(which will become empty after you leave), an empty square ".", a coin square "C" (which will become emptyafter you step on this square and thus collecting the coin), a rock square"O" or anobstacle square "X".
At each step, you can move onesquare to the up, down, left or right. You cannot leave the maze or enter anobstacle square, but you can push each rock at most once (i.e. You can treat arock as an obstacle square after you push it).
To push a rock, you must standnext to it. You can only push the rock along the direction you're facing, into anneighboring empty square (you can't push it outside the maze). For example, ifthe rock is to your immediate right, you can only push it to its rightneighboring square.
Find the maximal number of coinsyou can collect.
Input
The first line of input contains a singleinteger T (T<=25), the number of test cases. Each test casebegins with two integers r and c (2<=r,c<=10),then followed by r lines, each with c columns. There willbe at most 5 rocks and at most 10 coins in each maze.
Output
For each test case, print the maximalnumber of coins you can collect.
Sample Input Output forSample Input
3 3 4 S.OC ..O. .XCX 4 6 S.X.CC ..XOCC ...O.C ....XC 4 4 .SXC OO.C ..XX .CCC | 1 6 3 |
代码:
// Rujia Liu
#include<cstdio>
#include<cstring>
#include<cassert>
#include<vector>
#include<set>
using namespace std;
const int maxr = 10 + 5;
const int maxc = 10 + 5;
const int maxnr = 8 + 5;
const int maxnc = 8 + 5;
int r, c;
struct State {
int dep;
int x, y; // your position
int cnt; // how many coins are eaten
char maze[maxr][maxc];
int code() {
int ret = x*c + y;
for(int i = 0; i < r; i++) for(int j = 0; j < c; j++) ret = ret*257 + maze[i][j];
return ret * maxnc + cnt;
}
void print() {
printf("cnt = %d\n", cnt);
for(int i = 0; i < r; i++) {
for(int j = 0; j < c; j++)
printf("%c", (x==i && y==j) ? 'S' : maze[i][j]);
printf("\n");
}
}
};
set<int> vis;
// dfs2: find pushable rocks and eat coins
struct Candidate {
int x, y; // rock position
int d; // push direction
};
int vis2[maxr][maxc];
vector<Candidate> candi;
const int dx[] = {1, -1, 0, 0};
const int dy[] = {0, 0, 1, -1};
void dfs2(State& s, int x, int y) {
if(s.maze[x][y] == 'C') { s.maze[x][y] = '.'; s.cnt++; }
if(vis2[x][y]) return;
vis2[x][y] = 1;
for(int d = 0; d < 4; d++) {
int nx = x + dx[d];
int ny = y + dy[d];
if(nx < 0 || nx >= r || ny < 0 || ny >= c) continue;
if(s.maze[nx][ny] == 'O') {
int nx2 = nx + dx[d];
int ny2 = ny + dy[d];
if(nx2 >= 0 && nx2 < r && ny2 >= 0 && ny2 < c && s.maze[nx2][ny2] == '.')
candi.push_back((Candidate){nx, ny, d});
}
if(s.maze[nx][ny] == '.' || s.maze[nx][ny] == 'C') dfs2(s, nx, ny);
}
}
int best;
void dfs(State& s) {
if(vis.count(s.code())) return;
memset(vis2, 0, sizeof(vis2));
candi.clear();
dfs2(s, s.x, s.y);
best = max(best, s.cnt);
vector<Candidate> candi2(candi); // copy from global candidates
for(int i = 0; i < candi2.size(); i++) {
State s2;
memcpy(&s2, &s, sizeof(s));
s2.dep++;
int x = candi2[i].x;
int y = candi2[i].y;
int d = candi2[i].d;
s2.maze[x][y] = '.';
assert(s2.maze[x+dx[d]][y+dy[d]] == '.');
s2.maze[x+dx[d]][y+dy[d]] = 'X';
s2.x = x;
s2.y = y;
dfs(s2);
}
}
int main() {
int T;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &r, &c);
State start;
memset(&start, 0, sizeof(start));
start.x = -1;
for(int i = 0; i < r; i++) {
scanf("%s", start.maze[i]);
assert(strlen(start.maze[i]) == c);
for(int j = 0; j < c; j++)
if(start.maze[i][j] == 'S') {
start.x = i;
start.y = j;
start.maze[i][j] = '.';
}
}
assert(start.x != -1);
vis.clear();
best = -1;
dfs(start);
printf("%d\n", best);
}
return 0;
}