zoj 3103 Cliff Climbing (SPFA)

Cliff Climbing

Time Limit: 10 Seconds      Memory Limit: 32768 KB

At 17:00, special agent Jack starts to escape from the enemy camp. There is a cliff in between the camp and the nearest safety zone. Jack has to climb the almost vertical cliff by stepping his feet on the blocks that cover the cliff. The cliff has slippery blocks where Jack has to spend time to take each step. He also has to bypass some blocks that are too loose to support his weight. Your mission is to write a program that calculates the minimum time to complete climbing.

Figure D-1 shows an example of cliff data that you will receive. The cliff is covered with square blocks. Jack starts cliff climbing from the ground under the cliff, by stepping his left or right foot on one of the blocks marked with 'S' at the bottom row. The numbers on the blocks are the "slippery levels". It takes t time units for him to safely put his foot on a block marked with t, where 1 <= t <= 9. He cannot put his feet on blocks marked with 'X'. He completes the climbing when he puts either of his feet on one of the blocks marked with 'T' at the top row.


Figure D-1: Example of Cliff Data

Jack's movement must meet the following constraints. After putting his left (or right) foot on a block, he can only move his right (or left, respectively) foot. His left foot position (lx, ly) and his right foot position (rx, ry) should satisfy lx < rx and | lx - rx | + | ly - ry | <= 3. This implies that, given a position of his left foot in Figure D-2 (a), he has to place his right foot on one of the nine blocks marked with blue color. Similarly, given a position of his right foot in Figure D-2 (b), he has to place his left foot on one of the nine blocks marked with blue color.


Figure D-2: Possible Placements of Feet

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. Each dataset is formatted as follows:

w h
s(1,1)
... s(1,w)
s(2,1)
... s(2,w)
...
s(h,1) ... s(h,w)

The integers w and h are the width and the height of the matrix data of the cliff. You may assume 2 <= w <= 30 and 5 <= h <= 60. Each of the following h lines consists of w characters delimited by a space. The character s(y, x) represents the state of the block at position (x, y) as follows:

  • 'S': Jack can start cliff climbing from this block.
  • 'T': Jack finishes climbing when he reaches this block.
  • 'X': Jack cannot put his feet on this block.
  • '1' - '9' (= t): Jack has to spend t time units to put either of his feet on this block.

You can assume that it takes no time to put a foot on a block marked with 'S' or 'T'.

Output

For each dataset, print a line only having a decimal integer indicating the minimum time required for the cliff climbing, when Jack can complete it. Otherwise, print a line only having "-1" for the dataset. Each line should not have any characters other than these numbers.

Sample Input

6 6
4 4 X X T T
4 7 8 2 X 7
3 X X X 1 8
1 2 X X X 6
1 1 2 4 4 7
S S 2 3 X X
2 10
T 1
1 X
1 X
1 X
1 1
1 X
1 X
1 1
1 X
S S
2 10
T X
1 X
1 X
1 X
1 1
1 X
1 X
1 1
1 X
S S
10 10
T T T T T T T T T T
X 2 X X X X X 3 4 X
9 8 9 X X X 2 9 X 9
7 7 X 7 3 X X 8 9 X
8 9 9 9 6 3 X 5 X 5
8 9 9 9 6 X X 5 X 5
8 6 5 4 6 8 X 5 X 5
8 9 3 9 6 8 X 5 X 5
8 3 9 9 6 X X X 5 X
S S S S S S S S S S
10 7
2 3 2 3 2 3 2 3 T T
1 2 3 2 3 2 3 2 3 2
3 2 3 2 3 2 3 2 3 4
3 2 3 2 3 2 3 2 3 5
3 2 3 1 3 2 3 2 3 5
2 2 3 2 4 2 3 2 3 5
S S 2 3 2 1 2 3 2 3
0 0

Sample Output

12
5
-1
22
12

Source: Japan Domestic Contest 2007
Submit    Status

思路:
SPFA,将左脚和右脚分开看,每个位置到达的距离分为两个。 松弛操作就要从左脚推右脚,右脚推左脚了。因为相邻两次操作移动同一个脚是没有意义的,因为有一个脚没动,所以另一个脚的范围是不变得。

感想:
这题有多个起点和多个终点,而且每个起点只需一个脚放在起点就够了,开始没想到,连测试数据都得不到,坑了好久。。。

代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define maxn 70
using namespace std;

const int INF=0x3f3f3f3f;
int n,m,ans;
char mp[maxn][maxn];
int dist[maxn][maxn][2];
bool vis[maxn][maxn][2];
int dx1[]= {0,0,0,-1,-1,-2,1,1,2};
int dy1[]= {1,2,3,1,2,1,1,2,1};
int dx2[]= {0,0,0,-1,-1,-2,1,1,2};
int dy2[]= {-1,-2,-3,-1,-2,-1,-1,-2,-1};
char s[5];
struct Node
{
    int x,y;
    int flag;
} cur,now;
queue<Node>q;

void init()
{
    while(!q.empty()) q.pop();
    memset(dist,0x3f,sizeof(dist));
    memset(vis,0,sizeof(vis));
}
void SPFA()
{
    int i,j,t,nx,ny,tx,ty;
    while(!q.empty())
    {
        now=q.front();
        q.pop();
        nx=now.x;
        ny=now.y;
        vis[nx][ny][now.flag]=0;
        if(!now.flag)   // 左脚落地移右脚
        {
            for(i=0; i<9; i++)
            {
                tx=nx+dx1[i];
                ty=ny+dy1[i];
                if(!(tx>=1&&tx<=n&&ty>=1&&ty<=m)) continue ;
                if(mp[tx][ty]=='X') continue ;
                if(mp[tx][ty]=='S'||mp[tx][ty]=='T') t=0;
                else t=mp[tx][ty]-'0';
                if(dist[tx][ty][1]>dist[nx][ny][0]+t)
                {
                    dist[tx][ty][1]=dist[nx][ny][0]+t;
                    if(!vis[tx][ty][1])
                    {
                        vis[tx][ty][1]=1;
                        cur.x=tx;
                        cur.y=ty;
                        cur.flag=1;
                        q.push(cur);
                    }
                }
            }
        }
        else            // 右脚落地移左脚
        {
            for(i=0; i<9; i++)
            {
                tx=nx+dx2[i];
                ty=ny+dy2[i];
                if(!(tx>=1&&tx<=n&&ty>=1&&ty<=m)) continue ;
                if(mp[tx][ty]=='X') continue ;
                if(mp[tx][ty]=='S'||mp[tx][ty]=='T') t=0;
                else t=mp[tx][ty]-'0';
                if(dist[tx][ty][0]>dist[nx][ny][1]+t)
                {
                    dist[tx][ty][0]=dist[nx][ny][1]+t;
                    if(!vis[tx][ty][0])
                    {
                        vis[tx][ty][0]=1;
                        cur.x=tx;
                        cur.y=ty;
                        cur.flag=0;
                        q.push(cur);
                    }
                }
            }
        }
    }
}
int main()
{
    int i,j,k,mi;
    while(scanf("%d%d",&m,&n),m||n)
    {
        init();
        for(i=1; i<=n; i++)
        {
            for(j=1; j<=m; j++)
            {
                scanf("%s",s);
                mp[i][j]=s[0];
                if(s[0]=='S')
                {
                    dist[i][j][0]=dist[i][j][1]=0;
                    vis[i][j][0]=vis[i][j][1]=1;
                    cur.x=i;
                    cur.y=j;
                    cur.flag=0;
                    q.push(cur);
                    cur.flag=1;
                    q.push(cur);
                }
            }
        }
        SPFA();
        ans=INF;
        for(i=1; i<=m; i++)
        {
            if(mp[1][i]=='T')
            {
                mi=min(dist[1][i][0],dist[1][i][1]);
                if(ans>mi) ans=mi;
            }
        }
        if(ans==INF) ans=-1;
        printf("%d\n",ans);
    }
    return 0;
}




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值