poj 1178 Camelot

来源:互联网 发布:网络nat穿越 编辑:程序博客网 时间:2024/06/08 16:26
Camelot
Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 2466 Accepted: 1142

Description

Centuries ago, King Arthur and the Knights of the Round Table used to meet every year on New Year's Day to celebrate their fellowship. In remembrance of these events, we consider a board game for one player, on which one king and several knight pieces are placed at random on distinct squares.
The Board is an 8x8 array of squares. The King can move to any adjacent square, as shown in Figure 2, as long as it does not fall off the board. A Knight can jump as shown in Figure 3, as long as it does not fall off the board.

During the play, the player can place more than one piece in the same square. The board squares are assumed big enough so that a piece is never an obstacle for other piece to move freely.
The player's goal is to move the pieces so as to gather them all in the same square, in the smallest possible number of moves. To achieve this, he must move the pieces as prescribed above. Additionally, whenever the king and one or more knights are placed in the same square, the player may choose to move the king and one of the knights together henceforth, as a single knight, up to the final gathering point. Moving the knight together with the king counts as a single move.

Write a program to compute the minimum number of moves the player must perform to produce the gathering.

Input

Your program is to read from standard input. The input contains the initial board configuration, encoded as a character string. The string contains a sequence of up to 64 distinct board positions, being the first one the position of the king and the remaining ones those of the knights. Each position is a letter-digit pair. The letter indicates the horizontal board coordinate, the digit indicates the vertical board coordinate.

0 <= number of knights <= 63

Output

Your program is to write to standard output. The output must contain a single line with an integer indicating the minimum number of moves the player must perform to produce the gathering.

Sample Input

D4A3A8H1H8

Sample Output

10

题目大意:

有一种棋盘游戏,棋盘有8x8共64个方格,有两种棋子:国王和骑士,国王只有一个,骑士可以有多个。国王每移动一步可以从当前位置移动到八个方向的相邻方格(共有8种走法),移动的时候不能越界。骑士也是8种走法,但走的是“日”字,移动的时候也不能越界。当国王遇到骑士时,骑士可以带上国王,该骑士和国王看作一个骑士,按骑士走法走,每走一步只算一步(即国王从此可以忽略)。现在要求出将棋盘上所有骑士以及国王移动到相同方格需要的最少移动步数

解题思路:

使用枚举法,枚举最终的位置,国王与骑士相遇的位置,国王与哪个骑士相遇。

因为如果确定了最终的位置国王和骑士相遇的位置国王与哪个骑士相遇三个要素,则最少移动步数就确定了。

最终的位置共有64种,国王和骑士相遇的位置也有64种,设有N个骑士,则国王与哪个骑士相遇有N种,则枚举O(64*64*N)

对某个最终位置e,相遇位置m,遇到国王的骑士k,枚举时计算步骤如下:

1 计算所有骑士到e的最少移动步数。

2 加上国王移动到m的最少移动步数。

3 加上骑士k经过m到e的最少移动步数。

4 减去骑士k到e的最少移动步数。(骑士k在第1步中也算了一遍,所以要减去)

5 如果总的最少步数比当前已经求出的最少步数少,则更新最少步数。

枚举完后输出最后结果。

对于国王和骑士从某一点到另外一点的最少移动步数,采用floyd算法可以求出。

对棋盘的位置从0到63编号,A1为0,H8为63

king_map[i][j]表示国王从位置i到位置j最少的移动步数。

knight_map[i][j]表示骑士从位置i到位置j最少的移动步数。

为了在使用floyd算法前对king_map和knight_map进行初始化,使用两个二维数组表示国王和骑士从当前位置移动到8个位置的偏移量。

AC代码:
#include <iostream>#include <cstring>#include <string>#include <cstdio>#include <algorithm>#include <queue>#include <cmath>#include <vector>#include <cstdlib>using namespace std;const int INF=100000000;int king_move[8][2]={{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};int knight_move[8][2]={{1,-2},{2,-1},{2,1},{1,2},{-1,2},{-2,1},{-2,-1},{-1,-2}};int king_map[70][70];//国王从位置i到位置j的最少移动步数int knight_map[70][70];//骑士从位置i到位置j的最少移动步数bool ok(int x,int y)    //判断位置i是否合法{    if(x>=0&&x<8&&y>=0&&y<8)    return true;    return false;}void getxy(int p,int &x,int &y) //根据数字表示的位置获得坐标{    x=p%8;    y=p/8;}int getposition(int x,int y)  //根据坐标获得数字表示的位置   {    return x+y*8;}void init(){    for(int i=0;i<64;i++)    {        for(int j=0;j<64;j++)        {            king_map[i][j]=INF;            knight_map[i][j]=INF;        }        king_map[i][i]=0;        knight_map[i][i]=0;        int x,y,nx,ny;        int next;        getxy(i,x,y);        for(int j=0;j<8;j++)        {            nx=x+king_move[j][0];            ny=y+king_move[j][1];            if(ok(nx,ny))            {                next=getposition(nx,ny);                king_map[i][next]=1;            }            nx=x+knight_move[j][0];            ny=y+knight_move[j][1];            if(ok(nx,ny))            {                next=getposition(nx,ny);                knight_map[i][next]=1;            }        }    }}void floyd(){    for(int k=0;k<64;k++)    for(int i=0;i<64;i++)    for(int j=0;j<64;j++)    {        if(king_map[i][k]+king_map[k][j]<king_map[i][j])        king_map[i][j]=king_map[i][k]+king_map[k][j];        if(knight_map[i][k]+knight_map[k][j]<knight_map[i][j])        knight_map[i][j]=knight_map[i][k]+knight_map[k][j];    }}int main(){    string s;    int sum;    int p[70];    init();    floyd();    cin>>s;    int len=s.length();    int cnt=0;    for(int i=0;i<len;i+=2)    p[cnt++]=s[i]-'A'+(s[i+1]-'1')*8;    int min=INF;    for(int e=0;e<64;e++)  //枚举表示最终的位置    for(int m=0;m<64;m++)  //枚举国王与骑士相遇的位置    for(int k=1;k<cnt;k++)  //枚举与国王相遇的骑士    {        sum=0;        //计算所有骑士到终点的移动步数        for(int i=1;i<cnt;i++) sum+=knight_map[p[i]][e];        //加上国王到相遇地点的移动步数        sum+=king_map[p[0]][m];        //加上骑士k到相遇地点m再到终点的移动步数        sum+=knight_map[p[k]][m]+knight_map[m][e];        //减去骑士k到终点的移动步数(因为多算了一次)        sum-=knight_map[p[k]][e];        if(sum<min) min=sum;    }    cout<<min<<endl;    return 0;}


原创粉丝点击