1. 程式人生 > >poj 3009 Curling 2.0 (模擬 + dfs + 剪枝)

poj 3009 Curling 2.0 (模擬 + dfs + 剪枝)

Curling 2.0

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 26990 Accepted: 10757

Description

On Planet MM-21, after their Olympic games this year, curling is getting popular. But the rules are somewhat different from ours. The game is played on an ice game board on which a square mesh is marked. They use only a single stone. The purpose of the game is to lead the stone from the start to the goal with the minimum number of moves.

Fig. 1 shows an example of a game board. Some squares may be occupied with blocks. There are two special squares namely the start and the goal, which are not occupied with blocks. (These two squares are distinct.) Once the stone begins to move, it will proceed until it hits a block. In order to bring the stone to the goal, you may have to stop the stone by hitting it against a block, and throw again.

Fig. 1: Example of board (S: start, G: goal)

The movement of the stone obeys the following rules:

  • At the beginning, the stone stands still at the start square.
  • The movements of the stone are restricted to x and y directions. Diagonal moves are prohibited.
  • When the stone stands still, you can make it moving by throwing it. You may throw it to any direction unless it is blocked immediately(Fig. 2(a)).
  • Once thrown, the stone keeps moving to the same direction until one of the following occurs:
    • The stone hits a block (Fig. 2(b), (c)).
      • The stone stops at the square next to the block it hit.
      • The block disappears.
    • The stone gets out of the board.
      • The game ends in failure.
    • The stone reaches the goal square.
      • The stone stops there and the game ends in success.
  • You cannot throw the stone more than 10 times in a game. If the stone does not reach the goal in 10 moves, the game ends in failure.

Fig. 2: Stone movements

Under the rules, we would like to know whether the stone at the start can reach the goal and, if yes, the minimum number of moves required.

With the initial configuration shown in Fig. 1, 4 moves are required to bring the stone from the start to the goal. The route is shown in Fig. 3(a). Notice when the stone reaches the goal, the board configuration has changed as in Fig. 3(b).

Fig. 3: The solution for Fig. D-1 and the final board configuration

Input

The input is a sequence of datasets. The end of the input is indicated by a line containing two zeros separated by a space. The number of datasets never exceeds 100.

Each dataset is formatted as follows.

the width(=w) and the height(=h) of the board First row of the board  ... h-th row of the board

The width and the height of the board satisfy: 2 <= w <= 20, 1 <= h <= 20.

Each line consists of w decimal numbers delimited by a space. The number describes the status of the corresponding square.

0 vacant square
1 block
2 start position
3 goal position

The dataset for Fig. D-1 is as follows:

6 6  1 0 0 2 1 0  1 1 0 0 0 0  0 0 0 0 0 3  0 0 0 0 0 0  1 0 0 0 0 1  0 1 1 1 1 1

Output

For each dataset, print a line having a decimal integer indicating the minimum number of moves along a route from the start to the goal. If there are no such routes, print -1 instead. Each line should not have any character other than this number.

Sample Input

2 1
3 2
6 6
1 0 0 2 1 0
1 1 0 0 0 0
0 0 0 0 0 3
0 0 0 0 0 0
1 0 0 0 0 1
0 1 1 1 1 1
6 1
1 1 2 1 1 3
6 1
1 0 2 1 1 3
12 1
2 0 1 1 1 1 1 1 1 1 1 3
13 1
2 0 1 1 1 1 1 1 1 1 1 1 3
0 0

Sample Output

1
4
-1
4
10
-1

題意:打冰球。冰球可以往上下左右4個方向走,只有當冰球撞到牆時才會停下來,而牆會消失。當冰球緊貼牆時,不能將冰球往那個方向打。冰球出界就當輸,超過10次還沒將冰球打到目標位置也當輸。求用最小次數將冰球打到目標位置,或輸出-1表示輸了。

思路:dfs 模擬冰球的整個過程。此處 dfs 帶5個引數, dep 表示 已擊打的次數,typ表示 方向,x y 表示座標,flag 表示在運動過程中 或是 從靜止開始運動。 具體看程式碼

#include<cstdio>
#include<cstring>
#include<algorithm>
#define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair<int,int>
#define clr(a,b) memset((a),b,sizeof(a))
#define rep(i,a,b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define INT(t) int t; scanf("%d",&t)
#define LLI(t) LL t; scanf("%I64d",&t)

using namespace std;

char mp[30][30];
int to[4][2] = {1, 0, -1, 0, 0, 1, 0, -1}; /// 上到下, 下到上,左到右,右到左
int ty[4] = {0, 1, 2, 3};
int ans = 0, xxx;
int w, h;
int ex, ey;

void dfs(int dep, int typ, int x, int y, int flag) { /// typ = 0 從上到下, 1 從下到上,2 從左到右,3 右到左
    if(dep > 10)                     /// 剪枝,不合題意
        return ;
    if(dep > xxx) return ;          /// 剪枝,當前步數已經大於所算出的答案,可以直接 return
    //printf("x:%d y:%d\n",x,y);
    int tmpx = x + to[typ][0];
    int tmpy = y + to[typ][1];
    if(tmpx < 0 || tmpx >= h || tmpy < 0 || tmpy >= w)
        return ;
    if(tmpx == ex && tmpy == ey) {
        ans = 1;
        xxx = min(xxx,dep);
        return ;
    }

    if(mp[tmpx][tmpy] == '1') {
        if(!flag)                       /// flag != 1,也就是從靜止開始的,不能直接撞擊冰塊
            return ;
        mp[tmpx][tmpy] = '0';
        char oo[30][30];                /// 每一次 都需要新開一個char 陣列,可以理解為,在每個靜止處,都有向上或下或左或右走,每一種都是獨立的,不相互影響
        memcpy(oo,mp,sizeof(mp));
        for(int j = 0; j < 4; j ++){
            dfs(dep + 1, ty[j], x, y, 0);
            memcpy(mp,oo,sizeof(oo));
            //printf("2222 \n");
        }
    } else
        dfs(dep, typ, tmpx, tmpy, 1);
}

int main() {
    while(~scanf("%d%d", &w, &h) && (w || h)) {
        ans = 0; xxx = 0x3f3f3f3f;
        int bx, by;
        rep(i, 0, h)
        rep(j, 0, w) {
            scanf(" %c", &mp[i][j]);
            if(mp[i][j] == '2')
                bx = i, by = j;
            else if(mp[i][j] == '3')
                ex = i, ey = j;
        }
        char cop[30][30];
        memcpy(cop, mp, sizeof(mp));
        for(int i = 0; i < 4; i ++) {
            dfs(1, ty[i], bx, by, 0);// printf("1111 \n");
            memcpy(mp, cop, sizeof(cop));
        }
        if(!ans)
            printf("-1\n");
        else printf("%d\n",xxx);
    }
    return 0;
}