Betsy的旅行

题目: 

当N=3使,一种可能的路径如下:

普通的dfs回溯当然是会被卡的。

思路:对于一条合法的路径,除出发点和目标格子外,每一个中间格子都必然有“一进一出”的过程。所以在搜索过程中,必须保证每个尚未经过的格子都与至少两个尚未经过的格子相邻(除非当时Betsy就在它旁边)。

用一个数组last记录每个格子周围没访问过的格子数量,每次进入和退出一个格子的时候,都会更新他周围未访问格点的last数组。

当四周有一个格子last值为 1,则必须走这个格子。注意为了方便统一处理,终点的last值要增大 1。

代码如下:

import java.util.Scanner;

public class _Betsy的旅行 {
    static int n, ans;
    static int[] dx = {0, 0, 1, -1};//方向数组
    static int[] dy = {1, -1, 0, 0};
    static boolean[][] vis = new boolean[9][9];
    static int[][] last = new int[9][9];//数组last记录每个格子周围没访问过的格子数量

    static boolean in(int x, int y) {//判断越没越界
        return x >= 1 && x <= n && y >= 1 && y <= n;
    }

    static void dfs(int x, int y, int cnt) {
        if (x == n && y == 1) {//如果到了左下角的点
            if (cnt == n * n)//访问了全部的点
                ans++;
            return;
        }

        int dir = -1;//定义将要访问的方向
        vis[x][y] = true;//标记已访问
        for (int i = 0; i < 4; i++) {
            int ex = x + dx[i];//下一个要访问的点
            int ey = y + dy[i];
            if (in(ex, ey) && !vis[ex][ey]) {
                last[ex][ey]--;
                if (last[ex][ey] == 1) {//如果只剩下一个出口,只能访问这个
                    dir = i;
                }
            }

        }
        for (int i = 0; i < 4; i++) {
            if (dir != -1 && dir != i) continue;
            int tx = x + dx[i];
            int ty = y + dy[i];
            if (in(tx, ty) && !vis[tx][ty]) {
                boolean is_go = true;
                int r = 0;
                for (int j = 0; j < 4; j++) {
                    int ex = tx + dx[j];
                    int ey = ty + dy[j];
                    if (in(ex, ey) && !vis[ex][ey]) {
                        if (last[ex][ey] < 2) {//保证有2个,一进一出
                            is_go = false;
                            break;
                        } else if (last[ex][ey] == 2) {
                            r++;
                        }
                    }
                }
                if (is_go && r <= 1) {
                    dfs(tx, ty, cnt + 1);
                }
            }
        }
        vis[x][y] = false;
        for (int i = 0; i < 4; i++) {
            int tx = x + dx[i];
            int ty = y + dy[i];
            if (in(tx, ty) && !vis[tx][ty]) {
                last[tx][ty]++;
            }
        }
    }

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n; ++j) {
                for (int k = 0; k < 4; ++k) {
                    int tx = i + dx[k];
                    int ty = j + dy[k];
                    if (in(tx, ty))
                        ++last[i][j];
                }
            }
        }
        last[n][1]++;
        ans=0;
        dfs(1, 1, 1);
        System.out.println(ans);
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值