2010ACM-ICPC世界总决赛I题、UVA 1098 Robots on ice JAVA题解

博客主要介绍了2010年ACM-ICPC世界总决赛的I题——Robots on ice,并提供了UVA 1098题目的JAVA实现。作者在CSDN找到了两篇C/C++解题分享,但因需要JAVA版本,故根据原有逻辑实现了JAVA代码。虽然JAVA代码运行时间较C++慢,平均1360ms,相比其他答题者耗时较长,最快的解决方案仅用93ms。

Robots on ice

前言

最近算法课布置的作业是2010年acm世界总决赛的I题
UVA上题号1098,牛客网搜索题目可以搜到

题目原文不过多赘述可移步
博客1
题目中文解释及分析移步
博客2

以上是我在CSDN能找到的两篇分享,都是c/c++代码实现,由于本人需要JAVA实现,所以参照以上的解题逻辑写了JAVA版的题解,算法层面没有什么创新。在vjuge https://vjudge.net/problem/UVA-1098 上分别跑了上述博客中的c++代码和自己写的java代码,c++770ms,java1360ms。java明显耗时多挺多
vjuge测评结果
不过明显都比其他答题者的答案耗时长(一般耗时都在300ms左右)…最强的大佬竟然只用了93ms!
神犇
我的妈敢问是哪路神仙,这么优质的代码很遗憾没有共享,虽然我相信哪怕开源了我也看不懂代码逻辑…

JAVA实现

代码注释写的比较详细了,参考上述两篇博客可以看懂的。深搜加剪枝,关键在于剪枝条件的判定以及辅助的数据结构初始值指定。

import java.util.Scanner;
import static java.lang.Math.abs;

public class RobotsOnIce {
    int maxn = 11;
    int[][] dir = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}}; //上、右、下、左四个方向
    int n, m, l;            //n:列,m:行,l:总路长n*m
    int[] X = new int[5];  //指定的第i个检查点的坐标为(X[i],Y[i]),步数为C[i]
    int[] Y = new int[5];
    int[] C = new int[5];
    int[][] map;    //用于记录检测点的位置和序号,起点(0,0)序号为1,三个检测点为2、3、4,终点(0,1)序号为4.暂不初始化数组
    boolean[][] checked = new boolean[maxn][maxn];  //记录是否已走过某点
    int ans;                                        //答案,即可达路径数
    boolean[] b = new boolean[4];                   //存储四个方向是否合法(在界内且未走过)
    boolean cut(int x, int y){                      
    /*剪枝条件之一*/
        for (int i = 0; i < 4; ++i){
            int tx = x + dir[i][0];
            int ty = y + dir[i][1];
            b[i] = ((tx >= 0) && (tx < m) && (ty >= 0) && (ty < n) && !checked[tx][ty]);  //在界内且未走过
        }
        return ((b[0] && !b[1] && b[2] && !b[3]) || (!b[0] && b[1] && !b[2] && b[3]));    //如果上下(左右)可走左右(上下)不可走,则不可能成功,剪掉
    }

    void dfs(int x, int y, int c, int dep){
        if(dep == C[c]){                     //此时步数足够,理应到达对应的检测点
            if(map[x][y] == c) ++c;          //的确到达对应检测点,准备前往下一个
            else return;                     //实际上未到达,此路线确定不对无需再继续走,剪枝条件二
        }else if (map[x][y] > 0) return;     //步数还不够就走到检测点了,剪枝条件三

        if(dep == l){  //走完了
            ++ans;     //可达路径加一
            return;
        }

        if(abs(x - X[c]) + abs(y - Y[c]) > C[c] - dep) return;  //当前点到达下个检测点的最短路径比所需步数长,剪枝条件四

        for(int i = 0; i < 4; ++i){   //分别检查四个方向的相邻点的合法性,合法则尝试这条可能路线
            int tx = x + dir[i][0];
            int ty = y + dir[i][1];
            if ((tx >= 0) && (tx < m) && (ty >= 0) && (ty < n) && !checked[tx][ty] && !cut(tx, ty)){  //相邻点在界内、未走过、不会被条件一剪掉,则走向这个点
                checked[tx][ty] = true;
                dfs(tx, ty, c, dep+1);
                checked[tx][ty] = false;        //要恢复状态,不能影响下一次循环(即下一个走法)
            }
        }
    }

    void solve() {
        int count = 0;
        Scanner in = new Scanner(System.in);
        while(in.hasNext()){
             m = in.nextInt();
             n = in.nextInt();
             if(m == 0 && n == 0) break;
             map = new int[maxn][maxn];  //每次计算要重置数组,因为每次的检测点位置不同,确保除指定的检测点外其他点对应的map值为0
             l = n * m;
             for(int i = 1; i < 4; ++i){
                 X[i] = in.nextInt();
                 Y[i] = in.nextInt();
                 C[i] = i * l / 4;
                 map[X[i]][Y[i]] = i;
             }
            /*初始化*/
             X[4] = 0; Y[4] = 1; C[4] = l; map[0][1] = 4; ans = 0;   
            /*开始计算*/
             checked[0][0] = true;
             dfs(0, 0, 1, 1);
             checked[0][0] = false;
             System.out.printf("Case %d: %d\n", ++count, ans);
        }
    }

    public static void main(String[] args) {
        RobotsOnIce r = new RobotsOnIce();
        r.solve();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值