洛谷 P1930 亚瑟王的宫殿 Camelot

传送门

题目大意:棋盘有骑士有王,让所有点跳到一个点,求所有棋子跳的步数和,和最小。

题解:bfs+枚举

王的人生:

1):自己走到聚集点

2):某个骑士来到王这里,两个棋子一起到聚集点

3):王走几步,遇到骑士,再一起到聚集点

枚举聚集点O(nm),枚举去王那里的骑士O(nm*num),枚举

相遇的点O((nm)^2*num),假设骑士是n*m个,那么时间复

杂度是O((nm)^3)....时间复杂度绝对不行....

模拟一下发现,骑士和国王相遇的点,肯定在国王周围很近

的格子,所以枚举相遇的点复杂度不是O(nm)而是O(几乎没有)

BFS预处理每个点到每个点的最短距离dis[][][][],sum[i][j],表示聚集

点在(i,j)所有骑士都到(i,j)的距离和kingdis[i][j]表示国王到(i,j)的距离。

最后的距离公式是

所有骑士到枚举的聚集点的距离-枚举的骑士到聚集点的距离+枚举的骑

士相遇点的距离+相遇点的距离到聚集点的距离+国王到相遇点的距离。

时间复杂度是O(AC)  O(8nm+nm*numk)..我猜的

错因:最后的距离公式加晕头了,少加了一项。dis数组没有初始化,有些点不能跳到某些点。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath> 
#include<queue>
#define inf 2147483647
#define maxn 50
using namespace std;

char s[10];
int n,m,x,num,ans;
int dis[maxn][maxn][maxn][maxn],king_dis[maxn][maxn];
int vis[maxn][maxn],sum[maxn][maxn];
int mx[]={-2,-2,-1,-1,1,1,2,2},
    my[]={1,-1,2,-2,2,-2,1,-1};
struct node{
    int x,y,ste;
};
queue<node>q;
struct Node{
    int x,y;
}king,kni[maxn*maxn];

void BFS(int x,int y){
    memset(vis,0,sizeof(vis));
    while(!q.empty())q.pop();
    vis[x][y]=true;
    node now;now.x=x;now.y=y;now.ste=0;
    dis[x][y][x][y]=0;
    q.push(now);
    while(!q.empty()){
        node now=q.front();q.pop();
        int nx=now.x,ny=now.y,ste=now.ste;
        for(int i=0;i<8;i++){
            int nxtx=nx+mx[i],nxty=ny+my[i];
            if(nxtx<1||nxty<1||nxtx>n||nxty>m||vis[nxtx][nxty])continue;
            dis[x][y][nxtx][nxty]=dis[x][y][nx][ny]+1;
            vis[nxtx][nxty]=true;
            node tmp;tmp.x=nxtx;tmp.y=nxty;tmp.ste=ste+1;
            q.push(tmp); 
        } 
    }  
}

int main(){
    scanf("%d%d",&n,&m);ans=inf;
    scanf("%s%d",s,&x);king.x=x;king.y=s[0]-'A'+1;
    while(scanf("%s%d",s,&x)!=EOF){
        kni[++num].x=x;kni[num].y=s[0]-'A'+1;    
    }
    memset(dis,0x3f,sizeof(dis));
    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++)
      for(int k=1;k<=num;k++)
       sum[i][j]+=dis[kni[k].x][kni[k].y][i][j];
    for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
      king_dis[i][j]=max(abs(king.x-i),abs(king.y-j));
    for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
      ans=min(ans,sum[i][j]+king_dis[i][j]);
    for(int i=1;i<=n;i++)
      for(int j=1;j<=m;j++)
        for(int k=1;k<=num;k++)
          for(int nx=king.x-2;nx<=king.x+2;nx++)
            for(int ny=king.y-2;ny<=king.y+2;ny++)
              if(nx<1||ny<1||nx>n||ny>m)continue;
               else ans=min(ans,sum[i][j]-dis[kni[k].x][kni[k].y][i][j]+dis[kni[k].x][kni[k].y][nx][ny]+dis[nx][ny][i][j]+king_dis[nx][ny]);
    printf("%d
",ans);
    return 0;
}
AC
原文地址:https://www.cnblogs.com/zzyh/p/7739703.html