usaco Chapter 3 section 3.3 Camelot

来源:互联网 发布:ac尼尔森数据分析2016 编辑:程序博客网 时间:2024/05/17 10:39

/*

Camelot
IOI 98

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 chesspiece king and several knight pieces are placed on squares, no two knights on the same square.

This example board is the standard 8x8 array of squares:

The King can move to any adjacent square from to as long as it does not fall off the board:

A Knight can jump from to , 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 any 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 minimal 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 from that point on, 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. The pieces can gather on any square, of course.

*/

/*
ID: niepeng1
LANG: C++
TASK: camelot

不得不承认,我又参考了别人的程序。这次题目完全没有思路。最后看了题解发现国王搭载骑士的地点有限制只能在-2,+2 row col之间

最后发现时一次计算所有节点间的骑士步数,然后枚举结束点。计算没有国王的距离,最后再加上搭载国王的最短增加的步数就可以得到结果了。
*/
#include <iostream>
using namespace std;
#define MaxR 35
#define MaxC 30
FILE *in,*out;
int minSteps[MaxR][MaxC][MaxR][MaxC];
int visited[MaxR][MaxC];
int path[8][2]={
 -1,-2,
 -2,-1,
 -2, 1,
 -1, 2,
  1, 2,
  2, 1,
  2,-1,
  1,-2
};
struct lovekid{
 int row;//行
 int column;//列
}King,Knight[MaxR*MaxC],queue[MaxR*MaxC];
int R,C,cnt,ans=1<<30;

void Init()
{
 for(int i=1;i<=R;i++)
  for(int j=1;j<=C;j++)
   for(int ii=1;ii<=R;ii++)
    for(int jj=1;jj<=C;jj++)
     minSteps[i][j][ii][jj]=1<<25;
}
void Refresh()
{
 for(int i=1;i<=R;i++)
  for(int j=1;j<=C;j++)
   visited[i][j]=false;
}
int KingWay(int r,int c)
{
 int row=King.row-r;
 if(row<0)
  row=-row;
 int col=King.column-c;
 if(col<0)
  col=-col;
 return row>col?row:col;
}
void Bfs()
{
  int r,c,k,left,right,preR,preC,currentR,currentC;
  Init();
  for(r=1;r<=R;r++)
   for(c=1;c<=C;c++){
   Refresh();//更新访问标记
   left=right=0;//初始化数据
   queue[right].column=c;
   queue[right++].row=r;
   visited[r][c]=true;
   minSteps[r][c][r][c]=0;
   while(left<right){
    preR=queue[left].row;preC=queue[left++].column;
    for(k=0;k<8;k++){
  currentR=preR+path[k][0];currentC=preC+path[k][1];
  if(currentR>0&&currentR<=R&&currentC>0&&currentC<=C&&
   !visited[currentR][currentC]){
    queue[right].column=currentC;
    queue[right++].row=currentR;
    minSteps[r][c][currentR][currentC]=minSteps[r][c][preR][preC]+1;
    visited[currentR][currentC]=true;
  }
    }
   }
   }
}

void Solve(){
 int i,j,k,total,diffrence,r,c,kr,kc,tmp;
 bool cut;//剪枝,剪掉骑士不能到达的格子
 Bfs();
 for(i=1;i<=R;i++)
  for(j=1;j<=C;j++){//枚举终点
   total=0;
   cut=false;
    for(k=0;k<cnt;k++)
  if(minSteps[Knight[k].row][Knight[k].column][i][j]>=(1<<25)){
   cut=true;//遍历所有的骑士节点,如果有一个不能到,就放弃该节点
            break;
  }
  else total+=minSteps[Knight[k].row][Knight[k].column][i][j];
  if(cut||total>ans)continue;/*剪掉不能到达的格子和还没算王的路径已经大于或目前最有解的值格子*/
    diffrence=KingWay(i,j);
 //total存储当前不包含王的所有骑士汇聚到目标节点的距离
    for(r=-2;r<=2;r++)//最优解在的范围是王的坐标+-2
     for(c=-2;c<=2;c++){
      kr=King.row+r;
      kc=King.column+c;
      if(kr>0&&kr<=R&&kc>0&&kc<=C)//在边界内
       for(k=0;k<cnt;k++){//遍历所有骑士,如果求最小的载王去目的地点的距离
         tmp=minSteps[Knight[k].row][Knight[k].column][kr][kc]+
          minSteps[kr][kc][i][j]+KingWay(kr,kc)-
          minSteps[Knight[k].row][Knight[k].column][i][j];
         if(diffrence>tmp)//difference存储王直接走到目标节点的步数
          diffrence=tmp;
        }
     }
     total+=diffrence;
     if(ans>total)
      ans=total;
  }
  fprintf(out,"%d/n",ans);
}
void Read(){//读入数据
 in=fopen("camelot.in","r");
 out=fopen("camelot.out","w");
 char str[2];
 int input;
 fscanf(in,"%d%d",&R,&C);
 fscanf(in,"%s%d",str,&input);
 King.row=input;King.column=str[0]-'A'+1;//王的坐标
 while(fscanf(in,"%s%d",str,&input)!=EOF){//骑士的坐标
  Knight[cnt].row=input;Knight[cnt++].column=str[0]-'A'+1;
 }

}
int main()
{
 Read();
 Solve();
 return 0;
}

原创粉丝点击