这道题真的有太多小细节要注意了,如果没有usaco的测试数据指引,真的会漏掉非常多的细节
1. 首先我本地化了每个骑士(knightr,knightc){1=<knightr<=r,1=<knightc<=c}在给定row,col的棋盘上到达每个能到达方块的最小步数,这里特别要强调“可到达”,这个必须申明,因为行走基于可到达!
2. 同样,固化了国王的行路最小步数,当然国王只有一个.
3. 分析可能的情况:
condition 1:
国王不要骑士带领,直接走到汇合点,则步数为(all knights -> destination) + (king -> destination)
condition 2:
国王到了一个点,一个骑士赶到这个点(称为pickup),带着国王一起踏着骑士步到达汇合点,这里就是全部的搜索花费所在,(a specified knight -> pickup) + (king -> pickup) + (other knight -> destination) + (a specified knight -> destination)
接人点被证明在国王横纵坐标各相差2以内的位置,虽然不知道如何证明。。
思路就是这样,难点就在于,你需要根据你的本地数据,判断到底某个方案是否可行,即骑士是否能到达此终点,骑士能否到达接人点,骑士能否从接人点到达终点,这些都是需要考虑的问题,并且为了不超时,还得将循环中不变的数据尽量地提取出来,要知道数据亮还是不小的,重复计算,只会超时!!!真tm厉害!
我也无耻地贴代码了啊!!!!!!!干!
/*
NAME: songrgg1
PROG: camelot
LANG: C
*/
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#define min(a,b) (a)<(b)?(a):(b)
#define MAX 1<<29
int knight_move[31][27][31][27];
int king_move[31][27];
int knight[840][2];
int hash[31][27];
int knight_num=0;
char ch;
int r,c,t,ans,kingr,kingc;
struct _queue{
int r,c;
int step;
struct _queue *next;
};
struct _queue *head;
struct _queue *tail;
int kng_dir[8][2]={
{-1,-1},{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1}
};
int knt_dir[8][2]={
{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2}
};
void put(int row,int col,int step)
{
struct _queue *np=(struct _queue *)malloc(sizeof(struct _queue));
np->r=row;
np->c=col;
np->step=step;
if(head==NULL){
head=tail=np;
}else{
tail->next=np;
tail=np;
}
}
struct _queue *get()
{
if(head){
if(head==tail){
struct _queue *tmp=head;
head=tail=NULL;
return tmp;
}else{
struct _queue *tmp=head;
head=head->next;
return tmp;
}
}
return NULL;
}
int isEmpty()
{
return head==NULL;
}
void qinit()
{
while(head){
struct _queue *tmp=head;
head=head->next;
free(tmp);
}
head=tail=NULL;
}
void knight_move_init(int kr,int kc)
{
qinit();
memset(hash,0,sizeof(hash));
hash[kr][kc]=1;
knight_move[kr][kc][kr][kc]=0;
put(kr,kc,0);
while(!isEmpty()){
struct _queue *knt=get();
int i;
for(i=0;i<8;i++){
int newr=knt->r+knt_dir[i][0];
int newc=knt->c+knt_dir[i][1];
if(newr>0 && newc>0 && newr<=r && newc<=c && !hash[newr][newc]){
hash[newr][newc]=1;
put(newr,newc,knt->step+1);
knight_move[kr][kc][newr][newc]=knt->step+1;
}
}
free(knt);
}
}
void king_move_init()
{
qinit();
memset(hash,0,sizeof(hash));
hash[kingr][kingc]=1;
king_move[kingr][kingc]=0;
put(kingr,kingc,0);
while(!isEmpty()){
struct _queue *king=get();
int i;
for(i=0;i<8;i++){
int newr=king->r+kng_dir[i][0];
int newc=king->c+kng_dir[i][1];
if(newr>0 && newc>0 && newr<=r && newc<=c && !hash[newr][newc]){
hash[newr][newc]=1;
put(newr,newc,king->step+1);
king_move[newr][newc]=king->step+1;
}
}
free(king);
}
}
void init()
{
int i,j,k,l;
for(i=1;i<=r;i++){
for(j=1;j<=c;j++){
for(k=1;k<=r;k++){
for(l=1;l<=c;l++){
knight_move[i][j][k][l]=-1;
}
}
}
}
for(i=1;i<=r;i++){
for(j=1;j<=c;j++){
knight_move_init(i,j);
}
}
king_move_init();
}
int allknt2dest(int desr,int desc)
{
int i,ret=0;
for(i=0;i<knight_num;i++){
if(knight_move[knight[i][0]][knight[i][1]][desr][desc]==-1)
return -1;
ret+=knight_move[knight[i][0]][knight[i][1]][desr][desc];
}
return ret;
}
int aknt2pck_oth2dest(int aknt,int pckr,int pckc,int desr,int desc)
{
int aknt_r=knight[aknt][0];
int aknt_c=knight[aknt][1];
int i,ret=king_move[pckr][pckc];
if(knight_move[aknt_r][aknt_c][pckr][pckc]!=-1 &&
knight_move[pckr][pckc][desr][desc]!=-1){
ret+=knight_move[aknt_r][aknt_c][pckr][pckc];
ret+=knight_move[pckr][pckc][desr][desc];
for(i=0;i<knight_num;i++){
if(i!=aknt && knight_move[knight[i][0]][knight[i][1]][desr][desc]==-1)
return -1;
if(i!=aknt)
ret+=knight_move[knight[i][0]][knight[i][1]][desr][desc];
}
return ret;
}
return -1;
}
int check_dest(int desr,int desc)
{
int cnt=0,i,kno;
for(i=0;i<knight_num;i++){
if(knight_move[knight[i][0]][knight[i][1]][desr][desc]==-1){
cnt++;
kno=i;
}
}
if(cnt==0) return -1;
else if(cnt==1) return kno;
else return -2;
}
int dis(int desr,int desc)
{
int ret,_dis,i,j,k;
int check_ans=check_dest(desr,desc);
if(check_ans==-2) return MAX;
/*condition 1: if the king reach alone*/
if((_dis=allknt2dest(desr,desc))!=-1){
_dis+=king_move[desr][desc];
}
else
_dis=MAX;
ret=_dis;
if(check_ans==-1) {
for(i=kingr-2;i<=kingr+2;i++){
for(j=kingc-2;j<=kingc+2;j++){
if(i<1 || i>r || j<1 || j>r) continue;
if(knight_move[i][j][desr][desc]!=-1){
int tmp=king_move[i][j]+knight_move[i][j][desr][desc];
for(k=0;k<knight_num;k++){
tmp+=knight_move[knight[k][0]][knight[k][1]][desr][desc];
}
for(k=0;k<knight_num;k++){
if(knight_move[knight[k][0]][knight[k][1]][i][j]!=-1){
_dis=tmp-knight_move[knight[k][0]][knight[k][1]][desr][desc]+\
knight_move[knight[k][0]][knight[k][1]][i][j];
ret=min(ret,_dis);
}
}
}
}
}
} else {
/*condition 2: the king is carried by a soldier*/
for(i=kingr-2;i<=kingr+2;i++){
for(j=kingc-2;j<=kingc+2;j++){
if(i<1 || i>r || j<1 || j>r) continue;
/*we choose one knight to carry king*/
_dis=aknt2pck_oth2dest(check_ans,i,j,desr,desc);
if(_dis!=-1)
ret=min(_dis,ret);
}
}
}
return ret;
}
void solve()
{
int i,j;
int maxi,maxj;
ans=MAX;
for(i=1;i<=r;i++){
for(j=1;j<=c;j++){
/*suppose (i,j) is the destination*/
ans=min(ans,dis(i,j));
}
}
}
int main()
{
FILE *fin=freopen("camelot.in","r",stdin);
FILE *fout=freopen("camelot.out","w",stdout);
scanf("%d%d",&r,&c);
getchar();
scanf("%c%d",&ch,&t);
getchar();
kingc=ch-'A'+1; kingr=t;
while(2==scanf("%c%d",&ch,&t)){
getchar();
knight[knight_num][1]=ch-'A'+1;
knight[knight_num][0]=t;
knight_num++;
}
init();
solve();
printf("%d\n",ans);
fclose(fin);
fclose(fout);
return 0;
}