USACO 3.3 Camelot (camelot)

/*
Main Idea;
dist[x1][y1][x2][y2] denote the knight's min move from (x1,y1) to (x2,y2);
king_move_num[x][y] denote the king's min move from its initial place to the 
square it meet a knight.We can compute both of them by BFS;
total_dist[x][y] denote the total cost for king and knight to meet at square (x,y);
We choose the knight whose move "increase" lest to pick up king; Assume they meet at (x1,y1) and the
target square all knight and king meet is (x2,y2)
This knight and king's cost is dist[init_x][init_y][x1][y1] + dist[x1][y1][x2][y2] + king_move_num[x1][y1];
Note, we only cosider the range king and knight meet is +/-2 from king's initial place;
For knight i who don't pick up king, their cost is dist[x1][y1][x2][y2]; 
Sum all the cost we get total_dist[x2][y2];
Then we choose the min dist from total_dist;
*/
/*
Executing...
   Test 1: TEST OK [0.000 secs, 5900 KB]
   Test 2: TEST OK [0.000 secs, 5900 KB]
   Test 3: TEST OK [0.000 secs, 5900 KB]
   Test 4: TEST OK [0.011 secs, 5900 KB]
   Test 5: TEST OK [0.086 secs, 5900 KB]
   Test 6: TEST OK [0.130 secs, 5900 KB]
   Test 7: TEST OK [0.000 secs, 5900 KB]
   Test 8: TEST OK [0.000 secs, 5900 KB]
   Test 9: TEST OK [0.043 secs, 5900 KB]
   Test 10: TEST OK [0.205 secs, 5900 KB]
   Test 11: TEST OK [0.000 secs, 5900 KB]
   Test 12: TEST OK [0.000 secs, 5900 KB]
   Test 13: TEST OK [0.000 secs, 5900 KB]
   Test 14: TEST OK [0.000 secs, 5900 KB]
   Test 15: TEST OK [0.000 secs, 5900 KB]
   Test 16: TEST OK [0.000 secs, 5900 KB]
   Test 17: TEST OK [0.000 secs, 5900 KB]
   Test 18: TEST OK [0.000 secs, 5900 KB]
   Test 19: TEST OK [0.000 secs, 5900 KB]
   Test 20: TEST OK [0.000 secs, 5900 KB]

All tests OK.
*/
/*
ID: haolink1
PROG: camelot
LANG: C++
*/

//#include <iostream>
#include <fstream>
#include <cstring>
#include <queue>
using namespace std;
ifstream fin("camelot.in");
ofstream cout("camelot.out");
const int INF = 0x7FFFFFFF;
const int R_MAX = 30;
const int C_MAX = 26;
int R = 0, C = 0;
int move_knight[8][2] = {{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2}};
int move_king[8][2] = {{-1,-1},{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1}};
class Posi{
public:
    int row_;
    int col_;
    Posi():row_(0),col_(0){}
    Posi(const Posi& cur){
        row_ = cur.row_;
        col_ = cur.col_;
    }
    Posi(int row,int col):row_(row),col_(col){}
};
Posi king;
Posi king_range[25];
int range_num = 0;
Posi knight[780];
int knight_num = 0;
int dist[R_MAX][C_MAX][R_MAX][C_MAX];
int total_dist[R_MAX][C_MAX];
int king_move_num[R_MAX][C_MAX];

void BFS(Posi& init,int move[][2]){
    if(dist[init.row_][init.col_][init.row_][init.col_] != -1)
        return;//This place has one knight and its dist has been compute;
    dist[init.row_][init.col_][init.row_][init.col_] = 0;    
    queue<Posi> my_queue;
    my_queue.push(init);
    while(!my_queue.empty()){
        Posi cur = my_queue.front();
        my_queue.pop();
        for(int i = 0; i < 8; i++){
            int row = cur.row_ + move[i][0];
            int col = cur.col_ + move[i][1];
            if(row >= 0 && row < R && col >= 0 && col < C && dist[init.row_][init.col_][row][col] == -1){
                dist[init.row_][init.col_][row][col] = dist[init.row_][init.col_][cur.row_][cur.col_] + 1;
                my_queue.push(Posi(row,col));
            }
        }
    }
} 
void KingBFS(Posi& init,int move[][2]){
    memset(king_move_num,0xFF,sizeof(king_move_num));
    king_move_num[init.row_][init.col_] = 0;    
    queue<Posi> my_queue;
    my_queue.push(init);
    while(!my_queue.empty()){
        Posi cur = my_queue.front();
        my_queue.pop();
        for(int i = 0; i < 8; i++){
            int row = cur.row_ + move[i][0];
            int col = cur.col_ + move[i][1];
            if(row >= 0 && row < R && col >= 0 && col < C && king_move_num[row][col] == -1){
                king_move_num[row][col] = king_move_num[cur.row_][cur.col_] + 1;
                my_queue.push(Posi(row,col));
            }
        }
    }
} 

int ChooseKnight(int row,int col,int& num_chosen){
    int min_dist = INF, min_inc = INF;
    for(int i = 0; i < knight_num; i++){
        for(int j = 0; j < range_num; j++){
            int kin_r = king_range[j].row_, kin_c = king_range[j].col_;
            int kni_r = knight[i].row_,kni_c = knight[i].col_; 
            int d1 = dist[kni_r][kni_c][kin_r][kin_c];
            int d2 = dist[kin_r][kin_c][row][col];
            if(d1 < 0 || d2 < 0) continue; //Note in some case, the knight can't reach all squares, like R = 2, C = 26;
            //Note the below is wrong;
//          int cur_dist = d1 + d2 + abs(kin_r-king.row_)+abs(kin_c-king.col_);
            int cur_dist = d1 + d2 + king_move_num[kin_r][kin_c];
            int cur_inc = cur_dist - dist[kni_r][kni_c][row][col]; 
            if(min_inc > cur_inc){// we choose the knight whose move increase lest to pick up king;
                min_inc = cur_inc;
                min_dist = cur_dist;
                num_chosen = i;
            }
        }
    }
    return min_dist;
}

int main(){
    //Init;
    fin >> R >> C;
    int row = 0; 
    char col = 'A';
    fin >> col >> row;
    king.row_ = row - 1;
    king.col_ = col - 'A';
    while(fin >> col >> row){
        knight[knight_num].row_ = row - 1;
        knight[knight_num].col_ = col - 'A';
        knight_num++;
    }
    memset(dist,0xFF,sizeof(dist));

    //For knight
    for(int i = 0; i < knight_num; i++){
        BFS(knight[i],move_knight);
    }
    //For king
    //Compute King's min move to any other squares by BFS;
    KingBFS(king,move_king);
    //Compute King's Range to meet knight, here we enumerate +/- 2 of King's intial place;
    for(int i = -2; i <= 2; i++){
        for(int j = -2; j <= 2; j++){
            row = king.row_ + i;
            col = king.col_ + j;
            if(row >= 0 && row < R && col >= 0 && col < C){
                king_range[range_num].row_ = row;
                king_range[range_num].col_ = col;
                range_num++;
            }
        }
    } 
    //Compute min move in King's range to other squares;
    for(int i = 0; i < range_num; i++){
        BFS(king_range[i],move_knight);
    }
    if(knight_num > 0){
        for(int i = 0; i < R; i++){
            for(int j = 0; j < C; j++){
                int num_chosen = 0;
                total_dist[i][j] = ChooseKnight(i,j,num_chosen);
                for(int m = 0; m < knight_num; m++){
                    if(m == num_chosen) continue;
                    total_dist[i][j] += dist[knight[m].row_][knight[m].col_][i][j];
                }
            }
        }
    }
    int min_dist = INF;
    for(int i = 0; i < R; i++){
        for(int j = 0; j < C; j++){
            if(min_dist > total_dist[i][j])
                min_dist = total_dist[i][j];
        }
    }
    cout << min_dist << endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值