java擂台比较,[分享]《程序员》2007第九期算法擂台之JAVA代码

该博客介绍了如何使用Floyd-Warshall算法解决在8x8棋盘上寻找骑士最早聚会点的问题。作者通过将棋盘视为图,每个节点代表一格,边表示骑士可直接移动,进而计算出各节点间最短路径。程序以JAVA实现,通过动态规划找到骑士最少步数的聚会方案,并给出了详细的代码实现。
摘要由CSDN通过智能技术生成

[分享]《程序员》2007第九期算法擂台之JAVA代码

[url=http://eastsun.javaeye.com/blog/124477]本题JAVA及C++代码下载[/url]

原题:在8*8的棋盘上分布着n个骑士,他们想约在某一格中聚会.骑士每天可以像国际象棋中的马那样移动一次.请你计算n个骑士的最早聚会地点和要走多少天.要求尽早聚会,且n个人走的总步数最少,先到的骑士可以不再移动等待其它骑士.

输入:从键盘输入n(0<n<=64),然后依次输入n个骑士的初始位置xi,yi(0<=xi,yi<=7)

输出:以空格分隔的三个整数,分别为聚会点的x,y值,以及要走多少天

对问题的分析:为了解决这个问题,显然我们得想办法能计算出骑士从棋盘上的某个格子到其它格子需要的最少步数.

(另一方面,很容易可以证明骑士可以从棋盘上任意一个格子到达另一个格子)当然,最直接的想法是用搜索,挨个试一遍就OK了.

这也是种方法,如果加上动态规划,也是可行的算法.不过这里我没用这种方法,而是采用图论算法中已有的用于计算一个图中任意两点最短路径的经典算法--Floyd-Warshall算法.

我们可以将棋盘的64个格子看成64个节点,其中两个节点中存在一条边相连当且仅当骑士可以直接从其中的一个节点跳到另一个节点.这样骑士从棋盘某点到另一点需要移动的最少次数就转化为计算这个图中两个节点的最短路问题.至于Floyd-Warshall算法我就不多说了,随便baidu一下就知道.

剩下的问题就好办了,下面是我写的JAVA代码:

/**

Main.java

2007第九期算法擂台之JAVA代码

注: 该问题的解未必唯一,但根据问题需要,只给出一个解

另: 经测试,运行1000次new Knight()大约耗时6000毫秒

@author Eastsun

@version 1.0 2007/9/3

*/

import java.util.Scanner;

public class Main{

public static void main(String[] args){

Scanner scan =new Scanner(System.in);

int n =scan.nextInt();

int[][] pos =new int[n][2];

for(int index =0;index

pos[index][0] =scan.nextInt();

pos[index][1] =scan.nextInt();

}

ResultInf result =new Knight().solve(pos);

System.out.print(result.x +\" \" +result.y +\" \" +result.days);

}

}

class Knight{

private static final int DEFAULT_SIZE = 8;

private int boardSize;

//dis[i][j]表示骑士从棋盘上位置i到j所需的最少步数,其中位置i对于棋盘坐标(i%boardSize,i/boardSize)

private int[][] dist;

/**

Knight的构造函数

@param boardSize 棋盘的大小,默认值为8

*/

public Knight(int boardSize){

this.boardSize =boardSize;

initDist();

}

public Knight(){

this(DEFAULT_SIZE);

}

/**

根据骑士的位置求解

@param pos 一个int[][2]数组,第k个骑士的位置为(pos[k][0],pos[k][1])

@return result 该问题的解,注意:当result.days ==Integer.MAX_VALUE的时候说明这些骑士永远不可能聚在一起

*/

public ResultInf solve(int[][] pos){

if(pos ==null||pos.length ==0|| pos[0].length !=2) throw new IllegalArgumentException();

int location =0,days =Integer.MAX_VALUE,allDays =0;

for(int n =0;n

int max =0,sum =0;

for(int index =0;index

int dis = dist[n][pos[index][0]+pos[index][1]*boardSize];

sum += dis;

if(max

}

if(days>max ||(days==max&&allDays>sum)){

days =max;

allDays =sum;

location =n;

}

}

return new ResultInf(location%boardSize,location/boardSize,days);

}

/**

使用Floyd-Warshall算法计算dist的值,时间复杂度O(boardSize^6)

*/

private void initDist(){

int count =boardSize*boardSize;

dist =new int[count][count];

for(int n =0;n

for(int m =0;m

if(m!=n) dist[m][n] = isConnect(m%boardSize,m/boardSize,n%boardSize,n/boardSize)? 1: Integer.MAX_VALUE;

for(int k =0;k

for(int n =0;n

for(int m =0;m

if(dist[n][k]

dist[n][k]+dist[k][m]

dist[n][m] =dist[n][k] +dist[k][m];

}

/**

判断(x1,y1)与(x2,y2)是否直接可到

*/

private boolean isConnect(int x1,int y1,int x2,int y2){

return (x1!=x2&&y1!=y2&&Math.abs(x1-x2)+Math.abs(y1-y2)==3);

}

}

/**

一个用于保存求解信息的类

*/

class ResultInf{

public int x,y,days;

public ResultInf(int x,int y,int days){

this.x =x;

this.y =y;

this.days =days;

}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值