POJ3009 解题报告

来源:互联网 发布:淘宝童装排名 编辑:程序博客网 时间:2024/06/11 15:47
Curling 2.0
Time Limit: 1000MSMemory Limit: 65536KTotal Submissions: 21649Accepted: 8814

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.

0vacant square1block2start position3goal 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 13 26 61 0 0 2 1 01 1 0 0 0 00 0 0 0 0 30 0 0 0 0 01 0 0 0 0 10 1 1 1 1 16 11 1 2 1 1 36 11 0 2 1 1 312 12 0 1 1 1 1 1 1 1 1 1 313 12 0 1 1 1 1 1 1 1 1 1 1 30 0

Sample Output

14-1410-1

Source

Japan 2006 Domestic



这题写了好几个小时,还隔夜了, 深深地感受到了自己果然是个菜逼。。。。
我感觉这一题比较精彩的地方还是砖块的消除与恢复吧,这个类型的题目我还是第一次接触来着
每次进入搜索时都要消除刚刚碰到的石块,退出下一步搜索时又要将之前碰到的石块恢复,还是蛮有意思的


下面开始贴代码,代码里面的注释写的还是蛮详细的
不写注释的话过一段时间自己都看不懂自己写的是什么了

这是我第一次的代码
里面大体的话是没什么问题的,但是代码的第71行下面,在根据while循环结束条件进行分类处理的时候出了问题
我最开始的想法是如果是出界的话就不管他,只判断碰到石块或者是到达终点
但是这样会出现一个问题——如果while循环停止的原因是冰壶出界了,下面的if语句会当做是冰壶没有出界来处理。
这样会出现两种情况:
情况1:数组下标越界,oj报错runtime error
情况2:数组下标没越界,但是对于冰壶来说,它超出了场地的范围,那么范围之外数组的数据是不确定的,这会对结果造成影响。对于这一情况,举个例子,输入的数据是:第一行3 1,第二行2  1  3  那么就只有一行三列,若nx是行标,ny是列标,那么我的nx的最大值就是0,超过0的话,冰壶就越界了。那么当我的nx变成1,ny变成0的时候,
由于前面没有排除冰壶越界的情况,所以if语句还是会执行,比如if(num[nx][ny]==3),如果我上一次调用if语句的时候num[1][0]这个位置刚好是3,那我就错了喽(我测试的时候自己写的测试数据底下会贴出来)
这个问题我一开始是没发现的,自以为自己的代码写的很完美,wa了以后才开始找问题。。。。。。。。。。

#include<iostream>#include<algorithm>#include<set>using namespace std;const int maxw=22;const int maxh=22;int num[maxh][maxw];int dx[4]={-1,0,1,0};int dy[4]={0,1,0,-1};int sx,sy,gx,gy;int h,w;set<int>min_ans;void dfs(int x,int y,int ans);int main(){    while(cin>>w>>h)    {        if(w==0&&h==0) break;        for(int i=0;i<h;i++)            for(int j=0;j<w;j++)            {                cin>>num[i][j];                if(num[i][j]==2)                {                    sx=i;                    sy=j;                }                if(num[i][j]==3)                {                    gx=i;                    gy=j;                }            }        min_ans.clear();        dfs(sx,sy,0);        set<int>::iterator ite=min_ans.begin();        if(min_ans.size()) cout<<*ite<<endl;        else cout<<-1<<endl;    }    return 0;}void dfs(int x,int y,int ans){    ans++;    if(ans>10) return ;   //如果步数大于10了,说明失败了,退出这一次调用    for(int i=0;i<4;i++)    {        int nx=x+dx[i],ny=y+dy[i];  //选择一个方向抛出冰壶        if(num[nx][ny]==1) continue;        while(                  (0<=nx&&nx<h)&&   //判断nx有没有出界                  (0<=ny&&ny<w)&&   //判断ny有没有出界                  ( (num[nx][ny])!=3&&num[nx][ny]!=1 ) //判断是否到达终点或者是碰到石块             )        {            nx+=dx[i];  //以上条件都不满足的时候就继续向当前方向前进            ny+=dy[i];  //以上条件都不满足的时候就继续向当前方向前进        }        //循环结束,说明出现了上述情况,下面开始根据不同情况进行处理        if(num[nx][ny]==3) min_ans.insert(ans);  //成功到达终点则将步数插入集合中        else if(num[nx][ny]==1)     //碰到了石块,在石块的前一个位置停下来了        {            num[nx][ny]=0;  //由题意可知,碰到石块后,石块消失,于是将该位置设置为0            dfs(nx-dx[i],ny-dy[i],ans);     //冰壶停下来了,再一次抛出冰壶,进行下一轮搜索            num[nx][ny]=1;  //下一级搜索结束,这一级中该方向的搜索也结束了,于是将这个位置的石块恢复        }        //不满足上面两个条件的话说明到了边界,不进行任何操作,直接换一个方向重新开始    }}


下面是第二次的代码,这一次修改还是有问题的,因为我的判断越界的if语句里面的 !和()没有匹配好
#include<iostream>#include<algorithm>#include<set>using namespace std;const int maxw=22;const int maxh=22;int num[maxh][maxw];    //记录地图int dx[4]={-1,0,1,0};int dy[4]={0,1,0,-1};   //控制方向,下右上左int sx,sy,gx,gy;        //s起点,g终点int h,w;                //h行,w列set<int>min_ans;        //存放到达终点时的步数void dfs(int x,int y,int ans);int main(){    while(cin>>w>>h)    {        if(w==0&&h==0) break;        for(int i=0;i<h;i++)            for(int j=0;j<w;j++)            {                cin>>num[i][j];                if(num[i][j]==2)                {                    sx=i;                    sy=j;                }                if(num[i][j]==3)                {                    gx=i;                    gy=j;                }            }        min_ans.clear();        dfs(sx,sy,0);        set<int>::iterator ite=min_ans.begin();        if(min_ans.size()) cout<<*ite<<endl;        else cout<<-1<<endl;    }    return 0;}void dfs(int x,int y,int ans){    ans++;    if(ans>10) return ;   //如果步数大于10了,说明失败了,退出这一次调用    for(int i=0;i<4;i++)    {        int nx=x+dx[i],ny=y+dy[i];  //选择一个方向抛出冰壶        if(num[nx][ny]==1) continue;    //如果这个方向就是石块,抛不出去,就换一个方向        while(                  (0<=nx&&nx<h)&&   //判断nx有没有出界                  (0<=ny&&ny<w)&&   //判断ny有没有出界                  ( (num[nx][ny])!=3&&num[nx][ny]!=1 ) //判断是否到达终点或者是碰到石块             )        {            nx+=dx[i];  //以上条件都不满足的时候就继续向当前方向前进            ny+=dy[i];  //以上条件都不满足的时候就继续向当前方向前进        }        //循环结束,说明冰壶碰到了石块、到达终点、出界        if((!(0<=nx&&nx<h)&&(0<=ny&&ny<w))) continue;        else if(num[nx][ny]==3) min_ans.insert(ans);  //成功到达终点则将步数插入集合中        else if(num[nx][ny]==1)     //碰到了石块,在石块的前一个位置停下来了        {            num[nx][ny]=0;  //由题意可知,碰到石块后,石块消失,于是将该位置设置为0            dfs(nx-dx[i],ny-dy[i],ans);     //冰壶停下来了,再一次抛出冰壶,进行下一轮搜索            num[nx][ny]=1;  //下一级搜索结束,这一级中该方向的搜索也结束了,于是将这个位置的石块恢复        }        //不满足上面两个条件的话说明到了边界,不进行任何操作,直接换一个方向重新开始    }}

第三次代码
#include<iostream>#include<algorithm>#include<set>using namespace std;const int maxw=22;const int maxh=22;int num[maxh][maxw];    //记录地图int dx[4]={-1,0,1,0};int dy[4]={0,1,0,-1};   //控制方向,下右上左int sx,sy,gx,gy;        //s起点,g终点int h,w;                //h行,w列set<int>min_ans;        //存放到达终点时的步数void dfs(int x,int y,int ans);int main(){    while(cin>>w>>h)    {        if(w==0&&h==0) break;        for(int i=0;i<h;i++)            for(int j=0;j<w;j++)            {                cin>>num[i][j];                if(num[i][j]==2)                {                    sx=i;                    sy=j;                }                if(num[i][j]==3)                {                    gx=i;                    gy=j;                }            }        min_ans.clear();        dfs(sx,sy,0);        set<int>::iterator ite=min_ans.begin();        if(min_ans.size()) cout<<*ite<<endl;        else cout<<-1<<endl;    }    return 0;}void dfs(int x,int y,int ans){    ans++;    if(ans>10) return ;   //如果步数大于10了,说明失败了,退出这一次调用    for(int i=0;i<4;i++)    {        int nx=x+dx[i],ny=y+dy[i];  //选择一个方向抛出冰壶        if(num[nx][ny]==1) continue;    //如果这个方向就是石块,抛不出去,就换一个方向        while(                  (0<=nx&&nx<h)&&   //判断nx有没有出界                  (0<=ny&&ny<w)&&   //判断ny有没有出界                  ( (num[nx][ny])!=3&&num[nx][ny]!=1 ) //判断是否到达终点或者是碰到石块             )        {            nx+=dx[i];  //以上条件都不满足的时候就继续向当前方向前进            ny+=dy[i];  //以上条件都不满足的时候就继续向当前方向前进        }        //循环结束,说明冰壶碰到了石块、到达终点、出界        if(!((0<=nx&&nx<h)&&(0<=ny&&ny<w))) continue;        else if(num[nx][ny]==3) min_ans.insert(ans);  //成功到达终点则将步数插入集合中        else if(num[nx][ny]==1)     //碰到了石块,在石块的前一个位置停下来了        {            num[nx][ny]=0;  //由题意可知,碰到石块后,石块消失,于是将该位置设置为0            dfs(nx-dx[i],ny-dy[i],ans);     //冰壶停下来了,再一次抛出冰壶,进行下一轮搜索            num[nx][ny]=1;  //下一级搜索结束,这一级中该方向的搜索也结束了,于是将这个位置的石块恢复        }        //不满足上面两个条件的话说明到了边界,不进行任何操作,直接换一个方向重新开始    }}

最后下面是我的测试数据
3 91 1 13 0 01 0 01 0 01 0 01 0 02 0 10 0 01 0 15 11 2 1 1 33 91 1 13 0 01 0 01 0 01 0 01 0 02 0 10 0 01 1 13 61 1 13 0 01 0 02 0 10 0 01 1 12 12 33 12 1 3



原创粉丝点击