luogu P1649 [USACO07OCT]Obstacle Course S 矩阵中最小转弯次数路径 经典bfs或最短路

题目描述

Consider an N x N (1 <= N <= 100) square field composed of 1

by 1 tiles. Some of these tiles are impassible by cows and are marked with an ‘x’ in this 5 by 5 field that is challenging to navigate:

. . B x .
. x x A .
. . . x .
. x . . .
. . x . .

Bessie finds herself in one such field at location A and wants to move to location B in order to lick the salt block there. Slow, lumbering creatures like cows do not like to turn and, of course, may only move parallel to the edges of the square field. For a given field, determine the minimum number of ninety degree turns in any path from A to B. The path may begin and end with Bessie facing in any direction. Bessie knows she can get to the salt lick.

N*N(1<=N<=100)方格中,’x’表示不能行走的格子,’.’表示可以行走的格子。卡门很胖,故而不好转弯。现在要从A点走到B点,请问最少要转90度弯几次?
输入格式

第一行一个整数N,下面N行,每行N个字符,只出现字符:’.’,’x’,’A’,’B’,表示上面所说的矩阵格子,每个字符后有一个空格。

【数据规模】

2<=N<=100
输出格式

一个整数:最少转弯次数。如果不能到达,输出-1。
输入输出样例
输入 #1

3
. x A
. . .
B x .

输出 #1

2

说明/提示

【注释】

只可以上下左右四个方向行走,并且不能走出这些格子之外。开始和结束时的方向可以任意。


题意:跑二维地图,要求转弯次数最小

  • 观察到数据小,可以bfs
  • d[][]记录每个格子的最小转弯次数
  • 当方向相同时,不用转弯,即step=step,反之,方向不同就转弯,即step=step+1
  • 剪枝,当前格子的最小步数小于节点now就剪枝
  • 可以用spfa
// #define debug
#ifdef debug
#include <time.h>
#include "win_majiao.h"
#endif

#include <iostream>
#include <algorithm>
#include <vector>
#include <string.h>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <math.h>

#define MAXN (128)
#define ll long long int
#define INF (0x7f7f7f7f)
#define fori(lef, rig) for(int i=lef; i<=rig; i++)
#define forj(lef, rig) for(int j=lef; j<=rig; j++)
#define fork(lef, rig) for(int k=lef; k<=rig; k++)
#define QAQ (0)

using namespace std;
typedef vector<vector<int> > VVI;

#define show(x...) \
	do { \
		cout << "\033[31;1m " << #x << " -> "; \
		err(x); \
	} while (0)

void err() { cout << "\033[39;0m" << endl; }
template<typename T, typename... A>
void err(T a, A... x) { cout << a << ' '; err(x...); }

namespace FastIO{

	char print_f[105];
	void read() {}
	void print() { putchar('\n'); }

	template <typename T, typename... T2>
	   inline void read(T &x, T2 &... oth) {
		   x = 0;
		   char ch = getchar();
		   ll f = 1;
		   while (!isdigit(ch)) {
			   if (ch == '-') f *= -1; 
			   ch = getchar();
		   }
		   while (isdigit(ch)) {
			   x = x * 10 + ch - 48;
			   ch = getchar();
		   }
		   x *= f;
		   read(oth...);
	   }
	template <typename T, typename... T2>
	   inline void print(T x, T2... oth) {
		   ll p3=-1;
		   if(x<0) putchar('-'), x=-x;
		   do{
				print_f[++p3] = x%10 + 48;
		   } while(x/=10);
		   while(p3>=0) putchar(print_f[p3--]);
		   putchar(' ');
		   print(oth...);
	   }
} // namespace FastIO
using FastIO::print;
using FastIO::read;

int n, m, Q, K, S, E, si, sj, ei, ej;

int mtx[MAXN][MAXN], ID[MAXN][MAXN], D[MAXN][MAXN];
int dr[] = { 1, -1, 0, 0 },
	dc[] = { 0, 0, 1, -1 };

struct Edge {
	int v, w;
};
vector<Edge> G[MAXN*MAXN];

void conn(int i, int j) { }

struct Node {
	int r, c, 
		dir /* 方向有4个 : 0   1   2   3 */, 
		step /* 记录步数 */;
} ;

//CHECK_OUT 处理越界
#define CHECK_OUT { if(nr<1 || nc<1 || nr>n || nc>n || mtx[nr][nc]=='x') continue ; }
void bfs() {
	queue<Node> q;
	memset(D, INF, sizeof(D));
	D[si][sj] = 0; //起点和起点周围的4个点都应该是 0, 因为刚开始方向任意
	for(int i=0; i<4; i++) {
		int nr = si + dr[i], nc = sj + dc[i];
		CHECK_OUT
		Node no = { nr, nc, i, 0 }; 
		D[nr][nc] = 0;
		q.push(no);
	}

	while(!q.empty()) {
		Node& no = q.front();

		// 当前一定要更新,不然Wa到怀疑人生
		D[no.r][no.c] = min(D[no.r][no.c], no.step);
		
		for(int i=0; i<4; i++) {
			int nr = no.r + dr[i], nc = no.c + dc[i];
			CHECK_OUT //处理越界

			if(i == no.dir) { 
				// 方向相同就不用转身
				q.push({nr, nc, i, no.step});
				D[nr][nc] = min(no.step, D[nr][nc]);
			} else if(D[nr][nc] >= no.step+1) {
				// 方向不同就转身, 即 step+1
				D[nr][nc] = min(no.step + 1, D[nr][nc]);
				q.push({nr, nc, i, no.step + 1});
			}
		}
		q.pop();
	}
}

signed main() {
#ifdef debug
	freopen("test.txt", "r", stdin);
	clock_t stime = clock();
#endif
	ios::sync_with_stdio(false);
	scanf("%d ", &n);
	for(int i=1; i<=n; i++)
		for(int j=1; j<=n; j++) {
			scanf("%c ", &mtx[i][j]), ID[i][j] = (i-1)*n+j;
			if(mtx[i][j] == '.') conn(i, j);
			if(mtx[i][j] == 'A') S = ID[i][j], si = i, sj = j;
			if(mtx[i][j] == 'B') E = ID[i][j], ei = i, ej = j;
		}
	bfs();
	printf("%d\n", D[ei][ej] == INF ? -1 : D[ei][ej]);
	// for(int i=1; i<=n; i++) {
	// 	for(int j=1; j<=n; j++) printf("[%02d]  ", D[i][j]==INF ? 99 : D[i][j]);
	// 	printf("\n");
	// }





#ifdef debug
	clock_t etime = clock();
	printf("rum time: %lf 秒\n",(double) (etime-stime)/CLOCKS_PER_SEC);
#endif 
	return 0;
}




java代码






import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

public class Main {
    public static final boolean debug = true;
    public static String INPATH = "C:\\Users\\majiao\\Desktop\\test.txt",
            OUTPATH = "C:\\Users\\majiao\\Desktop\\out.txt";
    public static StreamTokenizer tok;
    public static BufferedReader cin;
    public static PrintWriter cout;

    public static long start_time = 0, out_time = 0;
    public static int n, m, K, Q, MAXN = (int)128, INF = 0x3f3f3f3f,
            pre[] = new int[MAXN], sum[] = new int[MAXN], POS = 50000;
    public static byte buf[] = new byte[MAXN];

    public static int fa(int x) { return pre[x]==x ? x : (pre[x]=fa(pre[x])); }

    public static void union_xy(int x, int y) {
        x = fa(x); y = fa(y);
        if(x != y) {
            sum[x] += sum[y];
            pre[y] = x;
        }
    }

    public static int si, sj, ei, ej,
                        dr[] = { 1, -1, 0, 0 },
                        dc[] = { 0, 0, 1, -1 };

    public static char mtx[][] = new char[MAXN][MAXN];
    public static int d[][] = new int[MAXN][MAXN];

    static class Node {
        int r, c, step, dir;

        public Node(int r, int c, int step, int dir) {
            this.r = r;
            this.c = c;
            this.step = step;
            this.dir = dir;
        }
    }

    public static int bfs() {
        for(int i=1; i<=n+1; i++)
            Arrays.fill(d[i], INF);
        Queue<Node> q = new LinkedList<>();
        d[si][sj] = 0;
        for(int i=0; i<4; i++) {
            int nr = si + dr[i], nc = sj + dc[i];
            if(nr<1 || nc<1 || nr>n || nc>n || mtx[nr][nc]=='x') continue ;
            q.add(new Node(nr, nc, 0, i));
        }
        while(!q.isEmpty()) {
            Node now = q.poll();
            d[now.r][now.c] = Math.min(d[now.r][now.c], now.step);
            for(int i=0; i<4; i++) {
                int nr = now.r + dr[i], nc = now.c + dc[i];
                if(nr<1 || nc<1 || nr>n || nc>n || mtx[nr][nc]=='x') continue ;
                if(now.dir == i) {
                    q.add(new Node(nr, nc, now.step, i));
                    d[nr][nc] = Math.min(d[nr][nc], now.step);
                } else if(d[nr][nc] >= now.step+1){
                    d[nr][nc] = Math.min(d[nr][nc], now.step+1);
                    q.add(new Node(nr, nc, now.step+1, i));
                }
            }
        }
        /**
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=n; j++) {
                cout.printf("[%c]  ", mtx[i][j]);
            }
            cout.println();
        }
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=n; j++) {
                cout.printf("[%d]  ", d[i][j]);
            }
            cout.println();
        }
         */
        return d[ei][ej];
    }

    public static void main(String[] args) throws IOException {
        main_init();
        if(debug) { start_time = System.currentTimeMillis(); }
        if(false) { System.setOut(new PrintStream(OUTPATH)); }
        
        Scanner scan = new Scanner(cin);
        String line = scan.nextLine();
        n = Integer.parseInt(line);
        for(int i=1; i<=n; i++) {
            line = scan.nextLine();
            String s = line.replaceAll(" ", "");
            char[] chars = s.toCharArray();
            for(int j=1; j<=n; j++) mtx[i][j] = chars[j-1];
        }

        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++) {
                if(mtx[i][j] == 'A') { si = i; sj = j; }
                if(mtx[i][j] == 'B') { ei = i; ej = j; }
            }
        bfs();
        cout.printf("%d\n", d[ei][ej] == INF ? -1 : d[ei][ej]);


        if(debug) {
            out_time = System.currentTimeMillis();
            cout.printf("run time : %d ms\n", out_time-start_time);
        }
        cout.flush();
    }

    public static void show(List<Object> list, Object... obj) {
        cout.printf("%s : ", obj.length>0 ? obj[0] : "");
        for(Object x : list) {
            cout.printf("[%s] ", x);
        }
        cout.printf("\n");
    }

    public static void show(Map<Object, Object> mp, Object... obj) {
        cout.printf("%s : ", obj.length>0 ? obj[0] : "");
        Set<Map.Entry<Object, Object>> entries = mp.entrySet();
        for (Map.Entry<Object, Object> en : entries) {
            cout.printf("[%s,%s] ", en.getKey(), en.getValue());
        }
        cout.printf("\n");
    }

    public static<T> void forarr(T arr[], int ...args) {
        int lef = 0, rig = arr.length - 1;
        if(args.length > 0) { lef = args[0]; rig = args[1]; }
        cout.printf(" : ");
        for( ; lef<=rig; lef++) {
            cout.printf("[%s] ", args[lef]);
        }
        cout.printf("\n");
    }

    public static void main_init() {
        try {
            if (debug) {
                cin = new BufferedReader(new InputStreamReader(
                        new FileInputStream(INPATH)));
            } else {
                cin = new BufferedReader(new InputStreamReader(System.in));
            }
            cout = new PrintWriter(new OutputStreamWriter(System.out));
//            cout = new PrintWriter(OUTPATH);
            tok = new StreamTokenizer(cin);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static String next_str() {
        try {
            tok.nextToken();
            if (tok.ttype == StreamTokenizer.TT_EOF)
                return null;
            else if (tok.ttype == StreamTokenizer.TT_NUMBER) {
                return String.valueOf((int)tok.nval);
            } else if (tok.ttype == StreamTokenizer.TT_WORD) {
                return tok.sval;
            } else return null;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static int read_int() {
        String tmp_next_str = next_str();
        return null==tmp_next_str ? -1 : Integer.parseInt(tmp_next_str);
    }
    public static long read_long() { return Long.parseLong(next_str()); }
    public static double read_double() { return Double.parseDouble(next_str()); }
    public static BigInteger read_big() { return new BigInteger(next_str()); }
    public static BigDecimal read_dec() { return new BigDecimal(next_str()); }


    static class Edge implements Comparable<Edge> {
        int u, v, w;
        @Override
        public int compareTo(Edge o) { return w - o.w; }
    }
    static Edge a[] = new Edge[MAXN];

    class Pair implements Comparable<Pair>{
        int fst, sec;
        public Pair() { }
        public Pair(int fst, int sec) {
            this.fst = fst;
            this.sec = sec;
        }
        @Override
        public int compareTo(Pair o) {
            return fst - o.fst == 0 ? sec - o.sec : fst - o.fst;
        }
    }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值