前言
这道题...坑点好多...不对,应该是我自己搞出来的坑点QAQ...
心好累...搞了一上午...
题目
题目描述
很久以前,亚瑟王和他的骑士习惯每年元旦去庆祝他们的友谊。为了纪念上述事件, 我们把这些故事看作是一个棋盘游戏。有一个国王和若干个骑士被放置在一个由许多方格 组成的棋盘上,没有两个骑士在同一个方格内。
这个例子是标准的 8*8 棋盘
国王可以移动到任何一个相邻的方格,从下图中黑子位置到下图中白子位置前提是他 不掉出棋盘之外。
一个骑士可以从下图中黑子位置移动到下图中白子位置(走“日”字形) 但前提是他 不掉出棋盘之外。
在游戏中,玩家可在每个方格上放不止一个棋子,假定方格足够大,任何棋子都不会 阻碍到其他棋子正常行动。
玩家的任务就是把所有的棋子移动到同一个方格里——用最小的步数。为了完成这个 任务,他必须按照上面所说的规则去移动棋子。另外,玩家可以选择一个骑士跟国王从他 们两个相遇的那个点开始一起行动,这时他们按照骑士的行动规则行动,其他的单独骑士 则自己一直走到集中点。骑士和国王一起走的时候,只算一个人走的步数。
请计算他们集中在一起的最小步数,而且玩家必须自己找出这个集中点。当然,这些 棋子可以在棋盘的任何地方集合。
输入格式
第一行: 两个用空格隔开的整数:R,C 分别为棋盘行和列的长。不超过 26 列,40 行。
第二行到结尾: 输入文件包含了一些有空格隔开的字母/数字对,一行有一个或以 上。第一对为国王的位置,接下来是骑士的位置。可能没有骑士,也可能整个棋盘都是骑 士。行从 1 开始,列从大写字母 A 开始。
输出格式
单独一行表示棋子集中在一个方格的最小步数。
输入输出样例
输入
8 8
D 4
A 3 A 8
H 1 H 8
输出
10
说明/提示
【样例说明】
他们集中在 B5。
骑士 1: A3 - B5 (1 步)
骑士 2: A8 - C7 - B5 (2 步)
骑士 3: H1 - G3 - F5 - D4 (此时国王开始与这个骑士一起走) - B5 (4 步) 骑士 4: H8 - F7 - D6 - B5 (3 步)
1 + 2 + 4 + 3 = 10 步
题目翻译来自NOCOW。
USACO Training Section 3.3
题目大意
方格棋盘上,有一些格子放了骑士或国王,一个格子只有一个,国王只有一个
每个格子可放多个棋子
骑士走“日”,王走“米”,且当一骑士在某一格与国王相遇后,二人可一起走,步数只算其中一人的
求所有骑士和国王都走到相同的某一个格子的最小总步数
分析
观察数据范围,发现十分“和蔼可亲”,于是做法可以考虑得暴力一点:
1.预处理出每个格子到另一个格子的距离,在每一个格子都做一遍BFS即可
2.枚举:
①和国王一起走的是哪个骑士
②所有棋子在哪个格子集合(目的地)
③接国王的骑士和国王在哪里相遇
3.更新答案
【“血泪史”中总结出的要点】
1.memset 初始化dis[ ]的话,很玄学,必须这样打:
memset(dis,0x10f,sizeof(dis));
0x3f 我又WA又TLE...
也可以这样初始化:
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) for(int k=1;k<=n;k++) for(int l=1;l<=m;l++) dis[i][j][k][l]=1000000;
2.注意枚举顺序和剪枝,不然TLE
3.国王不一定要和骑士一起走,注意一起走和不一起走这两种情况
4.“8*8”就是迷惑人的啊,棋盘可能比这个大,我最开始在这里卡了好久不知道哪里有问题,一定要好好看数据范围...
5.输入有技巧,gets()和单个字符输入我都试过,不好处理,所以直接质朴点,和平常一样地用“%s”
6.国王( x , y )到某个格子( i , j )的步数为max( abs( x - i ) , ( y - j ) )
因为国王走的“米”,有8个方向,不同于计算普通曼哈顿距离
奇怪的TLE代码
/*
ID:lunasmi2
TASK:camelot
LANG:C++
*/
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=40,INF=0x3f3f3f3f;
int dir1[10]={2,2,1,-1,-2,-2,-1,1},dir2[10]={-1,1,2,2,1,-1,-2,-2};
bool vis[MAXN+5][MAXN+5];
int dis[MAXN+5][MAXN+5][MAXN+5][MAXN+5];
int n,m,cnt,ans=INF;
int X,Y;//国王位置(X,Y)
struct node
{
int x,y,step;
}a[MAXN*MAXN+5];
void BFS(int x,int y)
{
memset(vis,0,sizeof(vis));
vis[x][y]=1;
dis[x][y][x][y]=0;
queue<node> que;
node q;
q.x=x,q.y=y,q.step=0;
que.push(q);
while(!que.empty())
{
q=que.front();que.pop();
for(int i=0;i<8;i++)
{
int dx=q.x+dir1[i],dy=q.y+dir2[i];
if(1<=dx&&dx<=n&&1<=dy&&dy<=m&&!vis[dx][dy])
{
vis[dx][dy]=1;
dis[x][y][dx][dy]=q.step+1;
node tmp;
tmp.x=dx,tmp.y=dy,tmp.step=q.step+1;
que.push(tmp);
}
}
}
}
int main()
{
//freopen("camelot.in","r",stdin);
//freopen("camelot.out","w",stdout);
scanf("%d%d",&n,&m);
char tmp1[5];
int tmp2;
scanf("%s %d",tmp1,&tmp2);
X=tmp2;
Y=tmp1[0]-'A'+1;
while(~scanf("%s %d",tmp1,&tmp2))
{
a[++cnt].x=tmp2;
a[cnt].y=tmp1[0]-'A'+1;
}
//预处理(i,j)到各方格的步数
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=1;k<=n;k++)
for(int l=1;l<=m;l++)
dis[i][j][k][l]=1000000;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
BFS(i,j);
for(int k=1;k<=cnt;k++)//第x个骑士护送国王
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)//国王和骑士从(i,j)开始一起走
for(int x=1;x<=n;x++)
for(int y=1;y<=m;y++)//目的地为(x,y)
{
int d,tot=0;
for(int t=1;t<=cnt;t++)//统计其他骑士的步数
if(t!=k)
tot+=dis[a[t].x][a[t].y][x][y];
d=dis[a[k].x][a[k].y][i][j]+max(abs(X-i),abs(Y-j))+dis[i][j][x][y]+tot;
ans=min(ans,d);
}
if(ans==INF)
printf("0\n");
else
printf("%d\n",ans);
return 0;
}
微调后AC代码
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=40,INF=0x3f3f3f3f;
int dir1[10]={2,2,1,-1,-2,-2,-1,1},dir2[10]={-1,1,2,2,1,-1,-2,-2};
bool vis[MAXN+5][MAXN+5];
int dis[MAXN+5][MAXN+5][MAXN+5][MAXN+5];
int n,m,cnt,ans=INF;
int X,Y;//国王位置(X,Y)
struct node
{
int x,y,step;
}a[MAXN*MAXN+5];
void BFS(int x,int y)
{
memset(vis,0,sizeof(vis));
vis[x][y]=1;
dis[x][y][x][y]=0;
queue<node> que;
node q;
q.x=x,q.y=y,q.step=0;
que.push(q);
while(!que.empty())
{
q=que.front();que.pop();
for(int i=0;i<8;i++)
{
int dx=q.x+dir1[i],dy=q.y+dir2[i];
if(1<=dx&&dx<=n&&1<=dy&&dy<=m&&!vis[dx][dy])
{
vis[dx][dy]=1;
dis[x][y][dx][dy]=q.step+1;
node tmp;
tmp.x=dx,tmp.y=dy,tmp.step=q.step+1;
que.push(tmp);
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
char tmp1[5];
int tmp2;
scanf("%s %d",tmp1,&tmp2);
X=tmp2;
Y=tmp1[0]-'A'+1;
while(~scanf("%s %d",tmp1,&tmp2))
{
a[++cnt].x=tmp2;
a[cnt].y=tmp1[0]-'A'+1;
}
//预处理(i,j)到各方格的步数
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=1;k<=n;k++)
for(int l=1;l<=m;l++)
dis[i][j][k][l]=1000000;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
BFS(i,j);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)//集合位置(i,j)
{
int tot=0;
for(int k=1;k<=cnt;k++)//统计其他骑士的步数
tot+=dis[a[k].x][a[k].y][i][j];
ans=min(ans,tot+max(abs(X-i),abs(Y-j)));
for(int k=1;k<=cnt;k++)
{
int dx=a[k].x,dy=a[k].y;
int t=tot-dis[dx][dy][i][j];
if(t>=ans)//最优性剪枝
continue;
for(int x=1;x<=n;x++)
for(int y=1;y<=m;y++)
ans=min(ans,t+dis[x][y][dx][dy]+dis[x][y][i][j]+max(abs(X-x),abs(Y-y)));
}
}
printf("%d\n",ans);
return 0;
}
总结
虽然自己打出的代码与正解大致相同,但是最初仍没有AC,还需历练啊