湖南省第八届程序设计竞赛I

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;
}



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值