标签:iostream line char play 题解 聚集 ring eof push
题目大意:棋盘有骑士有王,让所有点跳到一个点,求所有棋子跳的步数和,和最小。
题解: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\n",ans); return 0; }
标签:iostream line char play 题解 聚集 ring eof push
原文地址:http://www.cnblogs.com/zzyh/p/7739703.html