【USACO3-3-3】亚瑟王的宫殿 模拟

原题

1我们预处理一个数组dist[i][j][p][q]表示骑士从(i,j)到(p,q)要走的最短步数(直接用bfs即可)

2我们枚举每个点作为汇合点

3对于每个点第一种情况是,骑士不接国王走过去,国王自己走过去。第二种情况是有个骑士走过去接国王。

4第一种情况直接无脑加dist就行,对于第二种情况枚举每个骑士去接国王然后到汇合点所用步数,去最小值就行啦。

#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<cmath>

using namespace std;

#define inf 0x3f3f3f3f

struct node{int r,c;}king,knight[1009];
queue<node> qu;
char ch[11];
int dist[51][51][51][51],visit[1009][1009],
    dx[8]={1,2,2,1,-1,-2,-2,-1},
    dy[8]={2,1,-1,-2,-2,-1,1,2};
int n,m,tot=0,ans=inf;

bool check(int x,int y){return (x>0&&x<=n&&y>0&&y<=m);}
void bfs(int p,int q)
{
    memset(visit,0,sizeof(visit));visit[p][q]=1;dist[p][q][p][q]=0;qu.push((node){p,q});
    while(!qu.empty())
    {
        node k=qu.front();qu.pop();
        int step=dist[p][q][k.r][k.c];
        for (int i=0;i<8;i++)
        {
            int x=k.r+dx[i],y=k.c+dy[i];
            if (check(x,y)&&!visit[x][y])
            {
                visit[x][y]=1;
                dist[p][q][x][y]=step+1;
                qu.push((node){x,y});
            }
        }
    }
}

void init(){for (int i=1;i<=n;i++)for (int j=1;j<=m;j++)for (int p=1;p<=n;p++)for (int q=1;q<=m;q++) dist[i][j][p][q]=inf;}
int main()
{
    scanf("%d%d",&n,&m);
    scanf("%s%d",&ch,&king.r);king.c=ch[0]-'A'+1;
    while(~scanf("%s%d",&ch,&knight[++tot].r)) knight[tot].c=ch[0]-'A'+1;
    init();
    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++)
        {
            int res=0;bool f=true;
            for (int k=1;k<=tot;k++)
                if (dist[knight[k].r][knight[k].c][i][j]!=inf) res+=dist[knight[k].r][knight[k].c][i][j];else {f=false;break;}
            if (!f) continue;
            ans=min(ans,res+max(abs(king.r-i),abs(king.c-j)));
            for (int k=1;k<=tot;k++)
            {
                int temp=res-dist[knight[k].r][knight[k].c][i][j];
                if (temp>=ans) continue;
                for (int x=king.r-2;x<=king.r+2;x++)
                    for (int y=king.c-2;y<=king.c+2;y++)
                        if (check(x,y))ans=min(ans,temp+dist[x][y][i][j]+dist[x][y][knight[k].r][knight[k].c]+max(abs(king.r-x),abs(king.c-y)));
            }
        }
    printf("%d\n",ans);

    return 0;
}



猜你喜欢

转载自blog.csdn.net/Dadatu_Zhao/article/details/80441258