`
Eastsun
  • 浏览: 308858 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

《程序员》2007第九期之算法擂台

阅读更多

原题: 在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代码:

java 代码
  1. /**  
  2.    &#Main.java  
  3.    <程序员>2007第九期算法擂台之JAVA代码  
  4.    注: 该问题的解未必唯一,但根据问题需要,只给出一个解  
  5.    另: 经测试,运行1000次new Knight()大约耗时6000毫秒  
  6.    @author Eastsun  
  7.    @version 1.0 2007/9/3  
  8. */   
  9. import  java.util.Scanner;   
  10. public   class  Main{   
  11.      public   static   void  main(String[] args){   
  12.         Scanner scan = new  Scanner(System.in);   
  13.          int  n =scan.nextInt();   
  14.          int [][] pos = new   int [n][ 2 ];   
  15.          for ( int  index = 0 ;index<n;index ++){   
  16.             pos[index][ 0 ] =scan.nextInt();   
  17.             pos[index][ 1 ] =scan.nextInt();   
  18.         }   
  19.         ResultInf result = new  Knight().solve(pos);   
  20.         System.out.print(result.x + " "  +result.y + " "  +result.days);   
  21.     }   
  22. }   
  23.   
  24. class  Knight{   
  25.      private   static   final   int  DEFAULT_SIZE =  8 ;   
  26.        
  27.      private   int  boardSize;   
  28.        
  29.      //dis[i][j]表示骑士从棋盘上位置i到j所需的最少步数,其中位置i对于棋盘坐标(i%boardSize,i/boardSize)   
  30.      private   int [][] dist;   
  31.      /**  
  32.        Knight的构造函数  
  33.        @param boardSize 棋盘的大小,默认值为8  
  34.     */   
  35.      public  Knight( int  boardSize){   
  36.          this .boardSize =boardSize;   
  37.         initDist();   
  38.     }   
  39.      public  Knight(){   
  40.          this (DEFAULT_SIZE);   
  41.     }   
  42.      /**  
  43.        根据骑士的位置求解  
  44.        @param pos 一个int[][2]数组,第k个骑士的位置为(pos[k][0],pos[k][1])  
  45.        @return result 该问题的解,注意:当result.days ==Integer.MAX_VALUE的时候说明这些骑士永远不可能聚在一起  
  46.     */   
  47.      public  ResultInf solve( int [][] pos){   
  48.          if (pos == null ||pos.length == 0 || pos[ 0 ].length != 2 throw   new  IllegalArgumentException();   
  49.          int  location = 0 ,days =Integer.MAX_VALUE,allDays = 0 ;   
  50.          for ( int  n = 0 ;n<boardSize*boardSize;n ++){   
  51.              int  max = 0 ,sum = 0 ;   
  52.              for ( int  index = 0 ;index<pos.length;index ++){   
  53.                  int  dis = dist[n][pos[index][ 0 ]+pos[index][ 1 ]*boardSize];   
  54.                 sum += dis;   
  55.                  if (max<dis) max =dis;   
  56.             }   
  57.              if (days>max ||(days==max&&allDays>sum)){   
  58.                 days =max;   
  59.                 allDays =sum;   
  60.                 location =n;   
  61.             }   
  62.         }   
  63.          return   new  ResultInf(location%boardSize,location/boardSize,days);   
  64.     }   
  65.      /**  
  66.        使用Floyd-Warshall算法计算dist的值,时间复杂度O(boardSize^6)  
  67.     */   
  68.      private   void  initDist(){   
  69.          int  count =boardSize*boardSize;   
  70.         dist = new   int [count][count];   
  71.          for ( int  n = 0 ;n<count;n++)   
  72.              for ( int  m = 0 ;m<count;m++)   
  73.                  if (m!=n) dist[m][n] = isConnect(m%boardSize,m/boardSize,n%boardSize,n/boardSize)?  1 : Integer.MAX_VALUE;   
  74.                    
  75.          for ( int  k = 0 ;k<count;k++)   
  76.              for ( int  n = 0 ;n<count;n++)   
  77.                  for ( int  m = 0 ;m<count;m++)   
  78.                      if (dist[n][k]<Integer.MAX_VALUE&&dist[k][m]<Integer.MAX_VALUE&&   
  79.                           dist[n][k]+dist[k][m] <dist[n][m])   
  80.                               dist[n][m] =dist[n][k] +dist[k][m];   
  81.     }   
  82.      /**  
  83.        判断(x1,y1)与(x2,y2)是否直接可到  
  84.     */   
  85.      private   boolean  isConnect( int  x1, int  y1, int  x2, int  y2){   
  86.          return  (x1!=x2&&y1!=y2&&Math.abs(x1-x2)+Math.abs(y1-y2)== 3 );   
  87.     }   
  88. }   
  89.   
  90. /**  
  91.    一个用于保存求解信息的类  
  92. */   
  93. class  ResultInf{   
  94.      public   int  x,y,days;   
  95.      public  ResultInf( int  x, int  y, int  days){   
  96.          this .x =x;   
  97.          this .y =y;   
  98.          this .days =days;   
  99.     }   
  100. }  

 

 

这个是C++版:

cpp 代码
  1. /**  
  2.   注:: 对原题中  
  3.         "请你计算n个骑士的最早聚会地点和要走多少天.要求尽早聚会,且n个人走的总步数最少"  
  4.        感觉有歧义,不知道是"最早聚会"条件优先还是"走的总步数最少"条件优先.  
  5.        本代码中采用的是先考虑"最早聚会",其次考虑"走的总步数最少".另: 解未必唯一  
  6. **  
  7.   &#Together.cpp  
  8.   算法描叙:  
  9.       将棋盘上的SIZE*SIZE个位置看成SIZE*SIZE个节点,并且两个节点存在连线当且仅当马能够在这两个位置直接走动.  
  10.       定义两个节点m,n的距离dest[m][n]为马从m走到n所需的最少步数  
  11.       这样,可以通过Floyd-Warshall算法得到dest.  
  12.       算法的时间复杂度为O(SIZE^6),空间复杂度为O(SIZE^4)  
  13.       余略  
  14.    @author Eastsun  
  15.    @version 1.0 2007/9/3  
  16. */   
  17. #include<iostream>   
  18. #define X(n) ((n)&7)   
  19. #define Y(n) ((n)>>3)   
  20. #define P(x,y) ((x)+((y)<<3))   
  21. #define ABS(x) ((x)>=0?(x):-(x))   
  22.   
  23. // 棋盘的大小   
  24. const   int  SIZE = 8;   
  25.   
  26. // 一个用于表示"无限大"的数,只要比棋盘上任意两点的距离都大就OK   
  27. const   int  INFINITY = 2*SIZE*SIZE;   
  28.   
  29. // dest[m][n] 表示棋盘上m点到n点的距离   
  30. // 其中 棋盘上坐标为(x,y)的点对应dest中 x+y*8 的点   
  31. int  dest[SIZE*SIZE][SIZE*SIZE];   
  32.   
  33. /**  
  34.    点m与点n在棋盘上是否直接可到  
  35. */   
  36. bool  connected( int  m, int  n){   
  37.      int  x1 =X(m), y1 =Y(m);   
  38.      int  x2 =X(n), y2 =Y(n);   
  39.      return  ( (ABS(x1-x2)==2&&ABS(y1-y2)==1)||   
  40.              (ABS(x1-x2)==1&&ABS(y1-y2)==2)    
  41.             );   
  42. }   
  43.   
  44. /**  
  45.   计算dest的值  
  46. */   
  47. void  init(){   
  48.        
  49.      //初始化dest,将dest[n][n]设为0,可以直接到达的设为1,其余设为INFINITY   
  50.      for ( int  m =0;m< SIZE*SIZE; m++)   
  51.          for ( int  n =0;n< SIZE*SIZE; n++)   
  52.              if (m == n)   dest[m][n] = 0;   
  53.              else          dest[m][n] = connected(m,n)? 1: INFINITY;   
  54.                    
  55.      //计算dest   
  56.      for ( int  k=0;k< SIZE*SIZE; k++)   
  57.          for ( int  m=0;m< SIZE*SIZE; m++)   
  58.              for ( int  n=0;n< SIZE*SIZE; n++)   
  59.                  if (dest[m][n] >dest[m][k]+dest[k][n])   
  60.                     dest[m][n] =dest[m][k]+dest[k][n];   
  61. }   
  62.   
  63. int  main(){   
  64.     init();   
  65.      int  size;   
  66.     std::cin>>size;   
  67.      int  *pos = new   int [size];   
  68.      for ( int  i =0;i<size;i++){   
  69.          int  x,y;   
  70.         std::cin>>x>>y;   
  71.         pos[i] =P(x,y);   
  72.     }   
  73.      int  days =INFINITY,allDays,location;   
  74.      for ( int  m =0;m<SIZE*SIZE;m++){   
  75.          int  max =0,sum =0;   
  76.          for ( int  k =0;k<size;k++){   
  77.             sum += dest[m][pos[k]];   
  78.              if (dest[m][pos[k]] >max) max =dest[m][pos[k]];   
  79.         }   
  80.          if (max<days ||(max ==days&&sum<allDays) ){   
  81.             days =max;   
  82.             allDays =sum;   
  83.             location   =m;   
  84.         }   
  85.     }   
  86.      delete [] pos;   
  87.     std::cout<<X(location)<< " " <<Y(location)<< " " <<days;   
  88.      return  0;   
  89. }   

  • Source.rar (2.8 KB)
  • 描述: 本文中用到的代码
  • 下载次数: 32
分享到:
评论
2 楼 Eastsun 2007-09-21  
呵呵,楼上的代码我之前看了
我也加入pipboy圈子了,有机会一起交流~
1 楼 leon_a 2007-09-21  
这个题我同学发到pipboy圈子里,我还现买了一本《程序员》拿来看(浪费我10块钱,也没发现有什么好文章,总是拿些概念来说事),题目本身就有问题。不过找两点最短路径,我是用bfs+记录的方式,再用上小暴力搜索解决的。看到你的程序,也给我一些新鲜思路,有空一起圈子里讨论

相关推荐

    《程序员》第9期智慧擂台题目文件

    第9期的智慧擂台题目文件,无疑是为程序员们提供了一个提升技能、检验自身技术水平的平台。这次的主题聚焦在了技术文档的编写、程序员的基本素养以及通过实际题目来锻炼和展示程序员的解决问题能力。 技术文档是...

    《程序员》9期算法擂台“骑士聚会”源代码

    9期的算法擂台栏目聚焦于“骑士聚会”问题,这是一个涉及算法设计与实现的经典挑战。这个挑战源自于数学游戏,通常与图论或组合优化相关,旨在模拟中世纪骑士在棋盘上的排列方式。 "骑士聚会"问题来源于国际象棋,...

    《程序员编程艺术:面试和算法心得》

    《程序员编程艺术:面试和算法心得》是一本深入探讨编程面试和算法的书籍,主要针对的是准备面试的程序员,特别是那些关注技术深度和广度,以及如何在面试中展现出自己能力的开发者。这本书可能涵盖了从基础数据结构...

    程序员实用算法+源码(最后1个)

    程序员实用算法+源码,本书一共七个部分全部下载才可正常解压

    程序员编程艺术:面试和算法心得.pdf

    • 第六章 海量数据处理 o 6.0 本章导读 o 6.1 关联式容器 o 6.2 分而治之 o 6.3 simhash 算法 o 6.4 外排序 o 6.5 MapReduce o 6.6 多层划分 o 6.7 Bitmap o 6.8 Bloom filter o 6.9 Trie 树 o 6.10 数据库 o 6.11 ...

    程序员代码面试指南 IT名企算法与数据结构题目最优解.zip

    总之,《程序员代码面试指南》是一本全面且深入的资源,它不仅提供了大量的代码示例,还涵盖了理论知识和实践经验,对于希望提升自己算法能力、准备IT名企面试的程序员来说,是一本不可多得的宝典。

    程序员编程艺术系列之经典算法研究 电子书【高清中文带书签】

    A*搜索算法是一种在图中寻找最短路径的算法,它结合了最佳优先搜索和Dijkstra算法的优点,通过评估函数来估算从当前节点到目标节点的代价,从而决定下一个访问的节点。A*算法广泛应用于路径查找和图遍历问题,尤其是...

    2009年程序员杂志第九期

    《2009年程序员杂志第九期》是程序员们获取技术资讯、学习新知的重要参考资料。这期杂志可能涵盖了当年的热门技术趋势、编程语言的最新发展、软件工程的实践与创新、以及针对初级和高级程序员的职业发展建议等多个...

    程序员必备算法知识

    在IT行业中,算法是程序员解决问题的关键工具,它们是编程的基础,能够帮助我们高效地处理数据和执行任务。本文档集合中的四个PHP文档深入探讨了程序员应掌握的一些经典算法,这对于提升编程技能至关重要。 首先,...

    程序员实用算法.zip

    在IT行业中,算法是程序员的核心技能之一,它们是解决问题和设计高效程序的基础。"程序员实用算法.zip"这个压缩包很可能包含了一系列与编程相关的算法实现、解释或案例,旨在帮助程序员提升这方面的能力。以下是对...

    程序员06第9期 免分

    程序员06第9期 免分

    程序员的算法趣题.pdf.zip

    《程序员的算法趣题》是一本专门为IT从业者和有志于进入这个领域的学习者准备的算法书籍。它通过一系列有趣且富有挑战性的题目,旨在帮助读者深入理解和掌握计算机科学中的核心算法,提升解决实际问题的能力。这本书...

    程序员实用算法

    数据结构与算法是计算机科学的基础组成部分,对于程序员而言,掌握这些知识对于提升编程能力、解决实际问题以及提高软件开发效率至关重要。数据结构是组织和存储数据的方式,它决定了数据的存取效率和应用范围。而算...

    程序员实用算法源码

    程序员实用算法源码兼容VS2008及更高级的版本。在VS2008中可以直接运行,在VS2010中需先进行转换才能运行。 每个项目文件中,具体参数如何设置,是可以从源码的main函数中获得的,具体可以查看main函数中形如“...

    程序员算法趣题——随书源码

    《程序员算法趣题——随书源码》是一个与算法相关的学习资源,包含了增井敏克著作《程序员算法趣题》中的实例代码。增井敏克是算法领域知名的专家,他的书籍通常深入浅出,旨在帮助程序员提升算法思维和解决实际问题...

    2006程序员第九期

    2006程序员第九期

    程序员06第2期

    【标题】"程序员06第2期" 涉及的是一期专门针对程序员的杂志或期刊,这通常包含了丰富的IT技术文章、行业动态、编程技巧、软件开发实践等内容。"06第2期"表明这是该系列的第六个年份的第二期,可能包含了当年最前沿...

    程序员实用算法.pdf

    《程序员实用算法》这本书主要涵盖了计算机科学中程序员经常会遇到的各种算法,这些算法是解决实际问题、优化程序性能的关键。在编程领域,算法就如同工具箱中的各种工具,它们可以帮助程序员高效地处理数据,解决...

    程序员实用算法书中的源码

    《程序员实用算法书中的源码》是一本专为程序员设计的算法书籍,旨在提升程序员在实际工作中应用算法的能力。该书由(美)Andrew Binstock和John Rex合作撰写,并由陈宗斌等人翻译成中文。书中涵盖了一系列精选的...

    程序员必知必会经典算法

    在IT行业中,算法是程序员的核心技能之一,它们是解决问题和设计高效程序的基石。"程序员必知必会经典算法"这个主题涵盖了编程领域中的重要概念,包括基础算法和数据结构,这些都是C、C++等语言中不可或缺的部分。...

Global site tag (gtag.js) - Google Analytics