POJ 1178 Camelot (floyed算法)

本题没有读懂题目,想偏后导致各种不顺。我理解的是每个骑士间和国王都可以同步的移动。原来是一次只能移动一个人,求总步数最小。于是就简单多了。开始想歪后,在论坛找到一种说法:预处理+纯暴力。原文说“枚举64个终点 * 枚举64个接国王点 * 枚举64只来接的骑士 总复杂度O(64*64*64)”。这时候我才明白原来题目意思是要求求所有步数的最小值。Google题目的翻译。

这里是题目链接。题目大意:棋盘上有1个国王和若干个骑士,要把国王和每个骑士移动到同一个格子内,问需要移动的最小步数是多少。如果国王和骑士走到同一个格子里,可以由骑士带着国王一起移动。参考来源

题目转化为2张图,国王为点(实际上每一个格子都是点),每一个点到采用国王移动规则移到的另一个点为一条权值为1的边。Floyd算法可以算出每两点之间的最短路径,也就是国王从一点移动到另一点的最短步数。另外一张骑士的图同理。

于是算法转化为以上第一段说的三个枚举。我的代码如下:

   1: #include <iostream>
   2: #include <string>
   3: #include <algorithm>
   4:  
   5: using namespace std;
   6: const int MAX_INT = (1<<15);
   7: const int SQUARE_SIZE = 64;
   8:  
   9: int kings[SQUARE_SIZE][SQUARE_SIZE];
  10: int knights[SQUARE_SIZE][SQUARE_SIZE];
  11: int people[SQUARE_SIZE];
  12: const int kingsStep[8][2] = {{-1,-1},{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1}};
  13: const int knightsStep[8][2] = {{-1,-2},{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2}};
  14:  
  15: void initGraph()
  16: {
  17:     for (int i=0; i<SQUARE_SIZE; i++)
  18:     {
  19:         for (int j=0; j<SQUARE_SIZE; j++)
  20:             kings[i][j] = knights[i][j] = (i==j ? 0:MAX_INT); 
  21:     }
  22:     for (int i=0; i<SQUARE_SIZE; i++)
  23:     {
  24:         int fromX=i/8, fromY=i%8;
  25:         int toX, toY;
  26:         for (int j=0; j<8; j++)
  27:         {
  28:             toX=fromX+kingsStep[j][0];
  29:             toY=fromY+kingsStep[j][1];
  30:             if (toX>=0 && toX<8 && toY>=0 && toY<8)
  31:                 kings[i][8*toX+toY] = 1;
  32:             
  33:             toX=fromX+knightsStep[j][0];
  34:             toY=fromY+knightsStep[j][1];
  35:             if (toX>=0 && toX<8 && toY>=0 && toY<8)
  36:                 knights[i][8*toX+toY] = 1;
  37:         }
  38:     }
  39: }
  40:  
  41: void floyd()
  42: {
  43:     for (int k=0; k<SQUARE_SIZE; k++)
  44:     {
  45:         for (int i=0; i<SQUARE_SIZE; i++)
  46:         {
  47:             for (int j=0; j<SQUARE_SIZE; j++)
  48:             {
  49:                 kings[i][j] = min(kings[i][j], kings[i][k]+kings[k][j]);
  50:                 knights[i][j] = min(knights[i][j], knights[i][k]+knights[k][j]);
  51:             }
  52:         }
  53:     }
  54: }
  55:  
  56: int main()
  57: {
  58:     initGraph();
  59:     floyd();
  60:     string s;
  61:     cin >> s;
  62:     int count=s.size()/2;
  63:     for (size_t i=0, j=0; i<s.size(); i=i+2,j++)
  64:         people[j] =(s[i]-'A')+(s[i+1]-'1')*8;
  65:     
  66:     int res=MAX_INT;
  67:     int sum=0;
  68:     for (int end=0; end<SQUARE_SIZE; end++)
  69:     {
  70:         sum = 0;
  71:         for (int j=1; j<count; j++)
  72:             sum += knights[people[j]][end];
  73:         if (sum>res)    continue;
  74:         
  75:         for (int meet=0; meet<SQUARE_SIZE; meet++)
  76:         {
  77:             int step1=kings[people[0]][meet];
  78:             int step2=MAX_INT;
  79:             for (int k=1; k<count; k++)
  80:                 step2 = min(step2, knights[people[k]][meet]+knights[meet][end]-knights[people[k]][end]);
  81:             res = min(res, sum+step1+step2);
  82:         }
  83:     }
  84:     cout << res << endl;
  85:     s.clear();
  86:     return 0;
  87: }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值