poj1178

题意:一个国际象棋棋盘,有一个国王,和若干个骑士(马)。问要把他们都挪到一个格需要至少多少步。(国王如果和某骑士在同一个格则两者可以同时以骑士的方式移动且只记做一步)

分析:暴力枚举,跳马距离可先用floyd求。枚举终点,枚举国王上马地点,枚举国王要遇到的骑士。

View Code
#include < iostream >
#include
< cstdio >
#include
< cstdlib >
#include
< cstring >
using namespace std;

#define inf 0x3f3f3f3f
#define maxn 70

struct Point
{
int x, y;
} king, knight[maxn];

char st[ 256 ];
int dist[ 10 ][ 10 ][ 10 ][ 10 ];
int n;

void floyd()
{
for ( int i = 0 ; i < 8 ; i ++ )
for ( int j = 0 ; j < 8 ; j ++ )
for ( int k = 0 ; k < 8 ; k ++ )
for ( int l = 0 ; l < 8 ; l ++ )
if ((abs(i - k) == 1 && abs(j - l) == 2 ) || (abs(i - k)
== 2 && abs(j - l) == 1 ))
dist[i][j][k][l]
= 1 ;
else
dist[i][j][k][l]
= inf;
for ( int i = 0 ; i < 8 ; i ++ )
for ( int j = 0 ; j < 8 ; j ++ )
dist[i][j][i][j]
= 0 ;
for ( int i = 0 ; i < 64 ; i ++ )
for ( int j = 0 ; j < 64 ; j ++ )
for ( int k = 0 ; k < 64 ; k ++ )
{
int x1, x2, x3, y1, y2, y3;
x1
= i / 8 ;
x2
= j / 8 ;
x3
= k / 8 ;
y1
= i % 8 ;
y2
= j % 8 ;
y3
= k % 8 ;
dist[x2][y2][x3][y3]
= min(dist[x2][y2][x3][y3],
dist[x2][y2][x1][y1]
+ dist[x1][y1][x3][y3]);
}
}

void make()
{
king.x
= st[ 0 ] - ' A ' ;
king.y
= st[ 1 ] - ' 1 ' ;
for ( int i = 2 ; i < strlen(st); i += 2 )
{
int d = i / 2 - 1 ;
knight[d].x
= st[i] - ' A ' ;
knight[d].y
= st[i + 1 ] - ' 1 ' ;
}
n
= strlen(st) / 2 - 1 ;
}

void work()
{
if (n == 0 )
{
printf(
" 0\n " );
return ;
}
int ans = inf;
for ( int i = 0 ; i < 64 ; i ++ )
{
int x = i / 8 ;
int y = i % 8 ;
int sum = 0 ;
for ( int j = 0 ; j < n; j ++ )
sum
+= dist[x][y][knight[j].x][knight[j].y];
for ( int j = 0 ; j < 64 ; j ++ )
{
Point cross;
cross.x
= j / 8 ;
cross.y
= j % 8 ;
int temp1 = max(abs(king.x - cross.x), abs(king.y - cross.y));
int temp2 = inf;
for ( int k = 0 ; k < n; k ++ )
temp2
= min(temp2, dist[x][y][cross.x][cross.y]
+ dist[cross.x][cross.y][knight[k].x][knight[k].y]
- dist[x][y][knight[k].x][knight[k].y]);
ans
= min(ans, temp1 + temp2 + sum);
}
}
printf(
" %d\n " , ans);
}

int main()
{
// freopen("t.txt", "r", stdin);
scanf( " %s " , st);
floyd();
make();
work();
return 0 ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值