USACO/Camelot

USACO/Camelot

Posted by dym on May 25, 2014

本文迁移自老博客,原始链接为 https://seven.blog.ustc.edu.cn/usacocamelot/

棋盘上有一个王和n个骑士,王可以走直线或对角线,一次一格,骑士走日字。 问所有的棋子汇集到一格中所需的最少步数, 走的过程中,骑士可以接到王,然后骑士带着王一起走,此时只算骑士的步数。

解法:先预处理出所有的骑士到所有格的最短距离,使用bfs。 枚举所有的格子为终点,其中再枚举王的四周两层之内的格子为骑士接王的汇合点, 找到到此汇合点最近的骑士,算出接王所需的最少步骤, 加到到对应终点的距离和上。最终找出最少步数,格子不可达时或距离和已经大于当前最优值时可以剪枝

#include<iostream>
#include<queue>
#include<fstream>
using namespace std;
#define MAXR 32
#define MAXC 27
ofstream fout ("camelot.out");
ifstream fin ("camelot.in");
int kstep[MAXR][MAXC][MAXR][MAXC];
bool vis[MAXR][MAXC];
int path[8][2] = { {-1,-2},{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2} };
struct point
{
    int r;
    int c;
};
point king , knight[MAXR * MAXC];
int R,C,cnt;
int ans = 1<<30;
void init()
{
    for(int i=1; i<=R; i++)
        for(int j=1; j<=C; j++)
            for(int i1=1; i1<=R; i1++)
                for(int j1=1; j1<=C; j1++)
                    kstep[i][j][i1][j1]=1<<25;
}
void restore()
{
    for(int i=1; i<=R; i++)
        for(int j=1; j<=C; j++)
            vis[i][j]=false;
}
int KingWay(int r1 , int c1)
{
    int row = king.r - r1;
    if(row<0)row =- row;
    int column = king.c - c1;
    if(column<0)column=-column;
    return row > column ? row : column;
}
void BFS()
{
    int cR,cC;
    point tt , tt1 , tt2;
    init();
    for(int r1=1; r1<=R; r1++)
        for(int c1=1; c1<=C; c1++)
        {
            queue<point> que;
            restore();
            tt.c = c1;
            tt.r = r1;
            que.push(tt);
            vis[r1][c1]=true;
            kstep[r1][c1][r1][c1]=0;
            while(!que.empty())
            {
                tt1 = que.front();
                que.pop();
                for(int k=0; k<8; k++)
                {
                    cR=tt1.r + path[k][0];
                    cC=tt1.c + path[k][1];
                    if(cR>0&&cR<=R&&cC>0&&cC<=C&&
                            !vis[cR][cC])
                    {
                        tt2.c = cC;
                        tt2.r = cR;
                        que.push(tt2);
                        kstep[r1][c1][cR][cC]=kstep[r1][c1][tt1.r][tt1.c] + 1;
                        vis[cR][cC]=true;
                    }
                }
            }
        }
}
void input()
{
    char str;
    int input;
    fin>>R>>C;
    fin>>str>>input;
    king.r = input;
    king.c = str-'A'+1;
    while(fin>>str)
    {
        fin>>input;
        knight[cnt].r = input;
        knight[cnt++].c = str-'A'+1;
    }
}
void solve()
{
    int total,diff,kr,kc,tmp;
    bool cut;
    BFS();
    for(int i=1; i<=R; i++)
        for(int j=1; j<=C; j++)
        {
            total=0;
            cut=false;
            for(int k=0; k < cnt; k++)
            {
                if(kstep[knight[k].r][knight[k].c][i][j] >= (1<<25))
                {
                    cut=true;
                    break;
                }
                else 
                    total+=kstep[knight[k].r][knight[k].c][i][j];
            }
            if(cut||total>ans)continue;
            diff=KingWay(i,j);
            for(int r=-2; r<=2; r++)
                for(int c=-2; c<=2; c++)
                {
                    kr=king.r+r;
                    kc=king.c+c;
                    if(kr > 0 && kr <= R && kc > 0 && kc <= C)
                    {
                        for(int k = 0; k < cnt; k++)
                        {
                            tmp = kstep[knight[k].r][knight[k].c][kr][kc] +
                                kstep[kr][kc][i][j] + KingWay(kr,kc) -
                                kstep[knight[k].r][knight[k].c][i][j];
                            if(diff > tmp)
                                diff=tmp;
                        }
                   }
                }
            total+=diff;
            if(ans>total)
                ans=total;
        }
    fout<<ans<<endl;
}
int main()
{
    input();
    solve();
    return 0;
}