NOIP2013 华容道

图论好题。 介于网上全是些令蒟蒻头昏的题解和排版一塌糊涂以及过于详细的题解。。。蒟蒻记录一下。。

显然需要将白格移动到 \(s\) 相邻格,然后交换 \(s\) 与白格,再将白格移动到 \(s\) 相邻格,然后交换 \(s\) 与白格……最后一步将白格移动到 与 \(s\) 相邻的 \(t\) ,交换白格与 \(s\)。

我们考虑到,将格子 \(a\) 从 \((i,j)\) 移动到相邻的格子 \(b\),需要让白格先移动到 \(b\),之后交换 \(a\) 与白格。显然 \(a\) 下一步还是要继续往其他方向移动的,所以白格仍然需要移动到格子 \(a\) 的某个相邻格。

我们写了一个 bfs ,可以在白格在 \((ei,ej)\), s \((si,sj)\) 的时候处理一些值,接下来详细阐述。


现在所阐述的 bfs 是在代码中 \(k=0,1,2,3\) 时的 bfs ,用于预处理建图。

设置状态 \((i,j,k)\) 表示 格子 \(s\) 在 \((i,j)\) ,白格在 \((i,j)\) 的方向 \(k\) 处。( \(k\) : left right up down,用0,1,2,3表示)。

可以通过 bfs 计算出 状态 \((i,j,k)\) 时, 白格开始移动,移动到棋盘上任意一个格子 \((x,y)\) 的花费 \(dis_{x,y}\)。注意,在代码中,为了方便标记哪些是不可能移动到的点,将所有 \(dis_{x,y}\) 都加一了,但在题解中 \(dis_{x,y}\) 仍然是原先的值。

从状态 \((i,j,k)\) 转移到另一个状态,有两种情况。

  • 白格与 \(s\) 交换,在状态 \((si,sj,k)\) 与 \((ei,ej,k\and 1)\) 之间连边 1。
  • 白格移动到了一个与 \(s\) 相邻的位置 \((xx,yy)\) ,在状态 \((si,sj,k)\) 与状态 \((si,sj,i)\) 之间连边 \(dis_{xx,yy}\).

如果要计算状态 \((x1,y1,k1)\) 到状态 \((x2,y2,k2)\) 之间的最小花费,只需要跑最短路即可。

也就是说,我们把状态作为点,花费作为边建图。


现在阐述的是在代码中 \(k=4\) 时的 bfs,这是处理 白格到 初始格的相邻格 花费的 bfs。

仍然先处理出所有的 \(dis_{x,y}\) , 意义与求法同 \(k=0,1,2,3\) 时一样。将与 \(s\) 相邻格的 \(dis_{x,y}\) 赋值在 dist 上。

最后计算答案,只需要 spfa 计算 \((tx,ty,0/1/2/3)\) 到 \((sx,sy,0/1/2/3)\) 的最短路。

#include<bits/stdc++.h>
using namespace std;
const int N=35,M=4010;
int n,m,q,mp[N][N],dis[N][N],dist[M];
bool vis[M];
int e,to[M*5],nxt[M*5],val[M*5],hd[M];
int dx[5]={-1,1,0,0};
int dy[5]={0,0,-1,1};
void add(int x,int y,int w){ to[++e]=y; nxt[e]=hd[x]; val[e]=w; hd[x]=e; }
void bfs(int ei,int ej,int si,int sj,int dir){
memset(dis,0,sizeof(dis));
queue<pair<int,int> >q;
q.push(make_pair(ei,ej)); dis[ei][ej]=1;
while(!q.empty()){
pair<int,int>w=q.front(); q.pop();
int x=w.first,y=w.second;
for(int i=0;i<4;i++){
int xx=x+dx[i],yy=y+dy[i];
if(!mp[xx][yy]||dis[xx][yy]||xx==si&&yy==sj) continue;
dis[xx][yy]=dis[x][y]+1; q.push(make_pair(xx,yy));
}
}//白格向外疯狂移动处理步数
if(dir==4) return; for(int i=0;i<4;i++){
int xx=si+dx[i],yy=sj+dy[i];
if((xx==ei&&yy==ej)||!dis[xx][yy]) continue;
add(si*30*4+sj*4+dir,si*30*4+sj*4+i,dis[xx][yy]-1);//白格移动
}
add(si*30*4+sj*4+dir,ei*30*4+ej*4+(dir^1),1);//交换
return;
}
void spfa(int x,int y){
memset(dist,0x3f,sizeof(dist));
memset(vis,0,sizeof(vis)); queue<int>q;
for(int i=0;i<4;i++){
if(!dis[x+dx[i]][y+dy[i]]) continue;
int id=x*30*4+y*4+i; q.push(id);
dist[id]=dis[x+dx[i]][y+dy[i]]-1; vis[id]=1;
}
while(!q.empty()){
int id=q.front(); q.pop(); vis[id]=0;
// cout<<id<<endl;
for(int i=hd[id];i;i=nxt[i]){
int nxid=to[i],nxval=val[i];
// cout<<"nxid: "<<nxid<<endl;
if(dist[nxid]>dist[id]+nxval){
dist[nxid]=dist[id]+nxval;
if(vis[nxid]) continue;
vis[nxid]=1; q.push(nxid);
}
}
}
return;
}
int main(){
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&mp[i][j]);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(!mp[i][j]) continue;
if(mp[i-1][j]) bfs(i-1,j,i,j,0);
if(mp[i+1][j]) bfs(i+1,j,i,j,1);
if(mp[i][j-1]) bfs(i,j-1,i,j,2);
if(mp[i][j+1]) bfs(i,j+1,i,j,3);
}
}
//预处理,建图
while(q--){
int ex,ey,sx,sy,tx,ty;
scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty);
if(sx==tx&&sy==ty){ puts("0"); continue; } bfs(ex,ey,sx,sy,4); spfa(sx,sy); int ans=0x3f3f3f3f;
for(int i=0;i<4;i++) ans=min(ans,dist[tx*30*4+ty*4+i]);
(ans==0x3f3f3f3f)?puts("-1"):printf("%d\n",ans);
}
return 0;
}

最新文章

  1. oracle EXP导出一张表时使用query参数指定where条件
  2. (1)从底层设计,探讨插件式GIS框架的实现
  3. Linux基础-常用命令
  4. 64位MicrosoftOfficeWord加载EndnoteX7
  5. myeclipse的debug模式中breakpoint窗口怎么调出来
  6. JDK安装 配置环境变量
  7. OpenVPN莫名其妙断线的问题及其解决-confirm
  8. linux下添加PATH环境变量
  9. 【Asp.Net】后台生成控件并绑定事件
  10. java插入字符串
  11. leetCode之旅(14)-Number of 1 Bits
  12. Hibernate用注解生成表
  13. 网络-05-端口号-F5-负载均衡设-linux端口详解大全--TCP注册端口号大全备
  14. html和css问题?
  15. Hive学习01-基础常见问题
  16. 之手算KD-tree
  17. 根据数据库结构生成TreeView
  18. 【BZOJ】4361: isn
  19. windbg(1)
  20. 南昌网络赛 Distance on the tree 主席树+树剖 (给一颗树,m次查询ui-&gt;vi这条链中边权小于等于ki的边数。)

热门文章

  1. vuex前端工程化之动态导入文件--require.context( )
  2. windows下配置VSCode免密SSH连接Linux机器
  3. Spring Cloud Gateway 没有链路信息,我 TM 人傻了(中)
  4. java面向对象编程(上)
  5. fillder 抓包工具详解
  6. shell 基本语法介绍
  7. lightweight openpose 入门实操笔记(pytorch环境)
  8. Typescript, ES6
  9. PHP-设计模式之-中介者模式
  10. mysql允许别人通过ip访问本机mysql数据