Uestc381 - Knight and Rook

Uestc381 - Knight and Rook

题意:给定一个棋盘,起点为s,终点为t,有障碍物和空地,然后能够走的棋子有马和车,马走一步可以为周围8个L形,车可以垂直或者水平走,一步可以连续走多个格子,只要路线中没有障碍物,刚开始可以选定一个棋子,中间有一次交换棋子的机会,求最少需要多少步从起点走到终点。

 

分析:

1、  可以按照题目的意思,直接进行广搜,开始时有两种方式,即用马或者用车,所以进行两次bfs,每次扩展状态时如果当前没有换棋子,那么可以选择换旗子或者不换棋子走,否则只能按换过之后的方式走,注意用车走时得考虑当前方向所有能走的格子的情况。

2、  第二种方法的思路确实很巧妙而且值得掌握。既然在中间可以换一次棋子,那么对于每一个格子,求得一种棋子从s开始走到此处的最少步数加上另一种棋子从t开始走到此处的最少步数然后相加即可。

最后对所有格子取得最小值即可。所以首先预处理一个棋子分别从起点和终点开始走到每一个格子的最少步数,这个过程可以说是求最短路吧,然后还利用了动态规划的思想,相比第一种方法而言思路更值得学习和探讨。

其实广搜也是一种求最短路的方式,只不过每条边的权值相等而已,所以对于权值相等的最短路求解问题,可以直接进行广搜,而不需要dijstra算法,而且求最短路也相当于是进行动态规划。

这题是Ccpc杭州的热身赛,比赛时读错题意,以为rook每次只能走上下左右,然后自然是没做出来,正式比赛的时候A题合并数字没看到相邻这个单词,又读错题意了,导致后面直接的两个多小时卡死在上面…..哎,悲剧的打铁之旅。做任何事情有个总结总是好的,尤其是那些你有收获的,杭州ccpc之旅让我真正认识到了自身与强队之间的差距以及比赛时保持状态稳定的重要性,同时读题和写题要注意细节,要注重比赛时的技巧等等。


#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;

struct p{
    int x, y, s, f;
    p(int x = 0, int y = 0, int s = 0, int f = 0) : x(x), y(y), s(s), f(f) {}
};
int kdir[8][2] = {{-2, 1}, {-1, 2}, {1, 2}, {2, 1}, {2, -1}, {1, -2}, {-1, -2}, {-2, -1}};
int rdir[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
char s[110][110];
int n, m, sx, sy;
int vis[110][110][2];

int check(int x, int y, int f)
{
    return x >= 0 && x < n && y >= 0 && y < m && s[x][y] != '#';
}
int bfs()
{
    memset(vis, 0, sizeof(vis));
    vis[sx][sy][1] = 1;
    queue<p> q;
    q.push(p(sx, sy, 0, 1));
    while (!q.empty()){
        p t = q.front(); q.pop();
        int x = t.x, y = t.y;
        if (s[x][y] == 't') return t.s;
        for (int i = 0; i < 4; i++){
            int nx = x+rdir[i][0], ny = y+rdir[i][1];
            while (check(nx, ny, 0)){
                if (!vis[nx][ny][0]){
                    vis[nx][ny][0] = 1;
                    q.push(p(nx, ny, t.s+1, 0));
                }
                nx += rdir[i][0], ny += rdir[i][1];
            }
        }
        if (t.f){
            for (int i = 0; i < 8; i++){
                int nx = x+kdir[i][0], ny = y + kdir[i][1];
                if (check(nx, ny, 1) && !vis[nx][ny][1]){
                    vis[nx][ny][1] = 1;
                    q.push(p(nx, ny, t.s+1, 1));
                }
            }
        }
    }
    return INF;
}

int bfs2()
{
    memset(vis, 0, sizeof(vis));
    vis[sx][sy][0] = 1;
    queue<p> q;
    q.push(p(sx, sy, 0, 0));
    while (!q.empty()){
        p t = q.front(); q.pop();
        int x = t.x, y = t.y;
        if (s[x][y] == 't') return t.s;
        for (int i = 0; i < 8; i++){
            int nx = x+kdir[i][0], ny = y+kdir[i][1];
            if (check(nx, ny, 1) && !vis[nx][ny][1]){
                vis[nx][ny][1] = 1;
                q.push(p(nx, ny, t.s+1, 1));
            }
        }
        if (!t.f){
            for (int i = 0; i < 4; i++){
                int nx = x+rdir[i][0], ny = y+rdir[i][1];
                while (check(nx, ny, 0)){
                    if (!vis[nx][ny][0]){
                        vis[nx][ny][0] = 1;
                        q.push(p(nx, ny, t.s+1, 0));
                    }
                    nx += rdir[i][0], ny += rdir[i][1];
                }
            }
        }
    }
    return INF;
}

int main()
{
    int t, k = 0;
    scanf("%d", &t);
    while (t--){
        scanf("%d %d", &n, &m);
        int flag = 1;
        for (int i = 0; i < n; i++){
            scanf("%s", s[i]);
            for (int j = 0; j < m && flag; j++)
                if (s[i][j] == 's') sx = i, sy = j, flag = 0;
        }
        int ans = min(bfs(), bfs2());
        if (ans == INF)  printf("Case #%d: -1\n", ++k);
        else printf("Case #%d: %d\n", ++k, ans);
    }
    return 0;
}


#include <cstdio>
#include <algorithm>
#include <cstring>
#include <utility>
#include <queue>
#define INF 0x3f3f3f3f
#define LL long long
#define N 110
using namespace std;

typedef pair<int, int> p;
int dpk[2][N][N], dpr[2][N][N];
char s[N][N];
int m, n, sx, sy, tx, ty;
int kdir[8][2] = {{-2, 1}, {-1, 2}, {1, 2}, {2, 1}, {2, -1}, {1, -2}, {-1, -2}, {-2, -1}};
int rdir[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
int check(int x, int y)
{
    return x >= 0 && x < n && y >= 0 && y < m && s[x][y] != '#';
}
void kbfs(int xx, int yy, int f)
{
    memset(dpk[f], INF, sizeof(dpk[f]));
    dpk[f][xx][yy] = 0;
    queue <p> q;
    q.push(p(xx, yy));
    while (!q.empty()){
        p t = q.front(); q.pop();
        int x = t.first, y = t.second;
        for (int i = 0; i < 8; i++){
            int nx = x + kdir[i][0], ny = y + kdir[i][1];
            if (check(nx, ny) && dpk[f][nx][ny] == INF){
                dpk[f][nx][ny] = dpk[f][x][y] + 1;
                q.push(p(nx, ny));
            }
        }
    }
}
void rbfs(int xx, int yy, int f)
{
    memset(dpr[f], INF, sizeof(dpr[f]));
    dpr[f][xx][yy] = 0;
    queue <p> q;
    q.push(p(xx, yy));
    while (!q.empty()){
        p t = q.front(); q.pop();
        int x = t.first, y = t.second;
        for (int i = 0; i < 4; i++){
            int nx = x + rdir[i][0], ny = y + rdir[i][1];
            while (check(nx, ny)){
                if (dpr[f][nx][ny] == INF){
                    dpr[f][nx][ny] = dpr[f][x][y] + 1;
                    q.push(p(nx, ny));
                }
                nx += rdir[i][0], ny += rdir[i][1];
            }
        }
    }
}
int solve()
{
    kbfs(sx, sy, 0); kbfs(tx, ty, 1);
    rbfs(sx, sy, 0); rbfs(tx, ty, 1);
    int ans = INF;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++) {
            ans = min(ans, dpk[0][i][j] + dpr[1][i][j]);
            ans = min(ans, dpk[1][i][j] + dpr[0][i][j]);
        }
    return ans == INF ? -1 : ans;
}
int main()
{
    int t, k = 0;
    scanf("%d", &t);
    while (t--){
        scanf("%d %d", &n, &m);
        int flag = 1, tag = 1;
        for (int i = 0; i < n; i++){
            scanf("%s", s[i]);
            for (int j = 0; j < m && flag; j++)
                if (s[i][j] == 's') sx = i, sy = j, flag = 0;
            for (int j = 0; j < m && tag; j++)
                if (s[i][j] == 't') tx = i, ty = j, tag = 0;
        }
        printf("Case #%d: %d\n", ++k, solve());
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值