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明显耗时多挺多

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


被折叠的 条评论
为什么被折叠?



