前言
這道題...坑點好多...不對,應該是我自己搞出來的坑點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,還需歷練啊