初看这道题,想到纯暴力bfs , 但是套一个并查集优化 -1 的情况

但是要特判 出发点 与 目的点 重合的情况!!!!!! (score 10)

TLE&WA 代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smin(x,tmp) x=min(x,tmp)
#define smax(x,tmp) x=max(x,tmp)
const int maxn=35;
const int INF=0x3f3f3f3f;
const int dx[]={0,-1,0,1,0};
const int dy[]={0,0,-1,0,1};//u l d r
int n,m,q;
int g[maxn][maxn];
struct Coord
{int x,y;bool operator == (const Coord t)const{return x==t.x&&y==t.y;}
};
Coord fa[maxn][maxn];
Coord find(int x,int y)
{if(fa[x][y]==(Coord){x,y}) return fa[x][y];else return fa[x][y]=find(fa[x][y].x,fa[x][y].y);
}
inline bool union_find(int x,int y,int i,int j)
{Coord t1=find(x,y),t2=find(i,j);if(t1==t2) return false;fa[t2.x][t2.y]=t1;return true;
}
inline void init()
{scanf("%d%d%d",&n,&m,&q);for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&g[i][j]),fa[i][j]=(Coord){i,j};for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)for(int d=1;d<=2;d++){int x=i+dx[d],y=j+dy[d];union_find(x,y,i,j);}
}
struct Status
{int ei,ej;int ci,cj;Status (const int e1,const int e2,const int c1,const int c2){ei=e1,ej=e2;ci=c1,cj=c2;}bool check(int di,int dj){return ci==di && cj==dj;}bool operator < (const Status t) const{if(ei^t.ei) return ei<t.ei;if(ej^t.ej) return ej<t.ej;if(ci^t.ci) return ci<t.ci;return cj<t.cj;}
};
int f[maxn][maxn][maxn][maxn];//no need to use map!!
int bfs(Status S,int di,int dj)
{if(S.ei == di && S.ej == dj) return 0;// must judge here!! same node!!queue <Status> que;que.push(S);f[S.ei][S.ej][S.ci][S.cj]=0;while(!que.empty()){Status u=que.front();que.pop();int x0=u.ei,y0=u.ej;for(int i=1;i<=4;i++){int x=x0+dx[i],y=y0+dy[i];if(!g[x][y]) continue;Status v=u;v.ei=x,v.ej=y;if(x==v.ci && y==v.cj) v.ci=u.ei,v.cj=u.ej;int cost=f[u.ei][u.ej][u.ci][u.cj]+1;if(v.check(di,dj)) return cost;if(!f[v.ei][v.ej][v.ci][v.cj] || f[v.ei][v.ej][v.ci][v.cj]>cost) f[v.ei][v.ej][v.ci][v.cj]=cost,que.push(v);}}return -1;
}
int main()
{freopen("puzzle.in","r",stdin);freopen("puzzle.out","w",stdout);init();while(q--){int e1,e2,c1,c2,d1,d2;scanf("%d%d%d%d%d%d",&e1,&e2,&c1,&c2,&d1,&d2);if(find(e1,e2)==find(d1,d2)&&find(d1,d2)==find(c1,c2)) printf("%d\n",bfs(Status(e1,e2,c1,c2),d1,d2));else printf("-1\n");memset(f,0,sizeof(f));}return 0;
}

View Code

现考虑正解

由于每次移动都需要把空格移动到当前点四周

可以用 n2 次 O(n2) 的 bfs() 预处理出所有相邻情况

step[i][j][k][h] 表示当前点在 (i,j) 空格点在当前点的 k 方向上 ,并且要把空格移动到 h 方向上的最小步数

并且可以把当前点扣掉进行bfs

然后查询时分成从初始空格点到出发点 以及 当前点到目的点的两段!!!

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smin(x,tmp) x=min(x,tmp)
#define smax(x,tmp) x=max(x,tmp)
const int maxn=35;
const int INF=0x3f3f3f3f;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};//u d l r, u^1=d
int n,m,q;
int g[maxn][maxn];
int step[maxn][maxn][4][4];//i j, with the blank on the k side and l direction to move,but the blank node is to the opposite side, with which the target un moved!!
struct Coord
{int x,y;Coord (const int x0,const int y0) { x=x0;y=y0; }bool operator == (const Coord t) const{return x==t.x && y==t.y;}
};
inline bool inside(int x,int y)
{if(!g[x][y]) return false;return x>=1 && x<=n && y>=1 && y<=m ? true : false;
}
int d[maxn][maxn];//for bfs
int bfs(int si,int sj,int ti,int tj)
{if(!inside(si,sj) || !inside(ti,tj)) return INF;if(si==ti && sj==tj) return 0;queue <Coord> que;memset(d,0x3f,sizeof(d));d[si][sj]=0;que.push(Coord(si,sj));while(!que.empty()){int x0=que.front().x,y0=que.front().y;que.pop();for(int k=0;k^4;k++){int x=x0+dx[k],y=y0+dy[k];if(!inside(x,y)) continue;if(d[x][y]>d[x0][y0]+1){d[x][y]=d[x0][y0]+1;que.push(Coord(x,y));if(d[ti][tj]^INF) return d[ti][tj];}}}return INF;
}
inline void init()
{scanf("%d%d%d",&n,&m,&q);for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&g[i][j]);for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){int tmp=g[i][j];g[i][j]=0;// guarantee that no going though the target node!! BUT!!!!! MUST depend on its previous value!!!for(int k=0;k^4;k++)for(int l=0;l^4;l++)step[i][j][k][l]=bfs(i+dx[k],j+dy[k],i+dx[l],j+dy[l]);g[i][j]=tmp;//recovery
        }
}
int ei,ej,si,sj,ti,tj;
int dis[maxn][maxn][4];//for spfa(generally), from the point of(si,sj), with the function of judge vis!!
bool inque[maxn][maxn][4];
struct Node
{int x,y;int k;Node (const int x0,const int y0,const int k0) { x=x0,y=y0,k=k0; }
};
int spfa(int si,int sj,int ti,int tj)
{queue <Node> que;for(int k=0;k^4;k++)if(inside(si+dx[k],sj+dy[k]))que.push(Node(si,sj,k)),inque[si][sj][k]=true;// status must be the STARTing Node not the blank space node!!!while(!que.empty()){int x0=que.front().x,y0=que.front().y,k0=que.front().k;que.pop();inque[x0][y0][k0]=false;for(int k=0;k^4;k++){int x=x0+dx[k],y=y0+dy[k];if(!inside(x,y)) continue;if(dis[x][y][k^1] > dis[x0][y0][k0] + step[x0][y0][k0][k] +1){dis[x][y][k^1] = dis[x0][y0][k0] + step[x0][y0][k0][k] +1; // last status to the current status, and +1 to make the blank space exhanged to the opposite position!!if(!inque[x][y][k^1]) que.push(Node(x,y,k^1)) , inque[x][y][k^1]=true;}}}int ans = INF;for(int k=0;k^4;k++)// dont hand damn!!
        smin(ans,dis[ti][tj][k]);return ans^INF?ans:-1;//no need to +1 coz the ti tj is already here!!
}
int work()
{scanf("%d%d%d%d%d%d",&ei,&ej,&si,&sj,&ti,&tj);if(si==ti && sj==tj) return 0;if(!inside(si,sj) || !inside(ti,tj)) return INF;memset(dis,0x3f,sizeof(dis));int tmp=g[si][sj];g[si][sj]=0;// uncertain of its previous value!!for(int k=0;k^4;k++)if(g[si+dx[k]][sj+dy[k]]) dis[si][sj][k]=bfs(ei,ej,si+dx[k],sj+dy[k]);//from the start empty node to the START nodeg[si][sj]=tmp;return spfa(si,sj,ti,tj);
}
int main()
{freopen("puzzle.in","r",stdin);freopen("puzzle.out","w",stdout);init();while(q--)printf("%d\n",work());return 0;
}

View Code

转载于:https://www.cnblogs.com/ourfutr2330/p/5665080.html

[NOIP2013] 华容道相关推荐

  1. NOIP2013 华容道

    传送门 分析 暴力能拿 \(60\) ~ \(70pts\) . 具体的...以后再更吧 代码 #include <queue> #include <cstdio> #incl ...

  2. 刷题记录:牛客NC16536[NOIP2013]华容道

    传送门:牛客 题目描述: 题目较长,此处略 这道题的难度在洛谷上达到了紫题的水准,感觉还是有难度的( 花了我几乎5个小时 ),并且在没有看题解之前,根本不知道怎么做,脑中能想到的只有感觉会被T掉的算法 ...

  3. noip2017考前整理(未完)

    快考试了,把我以前写过的题回顾一下. Noip2007 树网的核:floyd,推出性质,暴力. Noip2008 笨小猴:模拟 Noip2008 火柴棒等式:枚举 Noip2008 传纸条:棋盘dp ...

  4. 语法入门*算法入门题单

    作者:王清楚 链接:https://ac.nowcoder.com/discuss/817596?type=101&order=0&pos=1&page=4&chann ...

  5. 【新手上路】语法入门算法入门题单

    作者:王清楚 链接:[新手上路]语法入门&算法入门题单_ACM竞赛_ACM/CSP/ICPC/CCPC/比赛经验/题解/资讯_牛客竞赛OJ_牛客网 来源:牛客网 介绍:本题单分为语法入门和算法 ...

  6. 算法初探系列5 - 广度优先搜索之状态表示

    概述 上节课我们学习了在简单迷宫问题中如何使用BFS求解,这次我们来讲解一下较复杂 ~~(花里胡哨)~~ 的迷宫问题 复习+延伸(多起点BFS) 在普通bfs问题中,我们先将起点入队,然后一直从起点延 ...

  7. 【题解】P1979 [NOIP2013 提高组] 华容道(SPFA,BFS,常数优化)

    [题解]P1979 [NOIP2013 提高组] 华容道 最近打比赛次次挂..平均每周得被至少一场比赛打击一次(这周好不容易 ABC 打的还行模拟赛又挂--)心烦意乱.写篇题解疏散一下内心的苦闷(雾) ...

  8. 【NOIP2013】华容道 最短路优化搜索(spfa)

    华容道 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 34  Solved: 14 [Submit][Status][Web Board] Descr ...

  9. python华容道最短路径_SSOJ1322华容道(NOIP2013)

    题目大意:在一个棋盘上,0不能做,1可以走,现在要将一个棋子移动到目标位置,移动时只能跟空格(只有一个)交换位置,至少要多少步? 题目描述 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一 ...

  10. P1979 [NOIP2013 提高组] 华容道

    题目来源 [NOIP2013 提高组] 华容道 - 洛谷 题目考点 搜索   图论 题目 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面, ...

最新文章

  1. 面试:为什么 Java 线程没有Running状态?
  2. 支付宝能扫码闪电开发票了!人均省时3分钟
  3. WPF 触发器Triggers
  4. salesforce 零基础学习(四十二)简单文件上传下载
  5. 最后一个单词的长度Python解法
  6. 架构师之路 扩充字段_扩大您作为设计师的业务影响力的四个基础
  7. java web的友好页面_JavaWeb 之 由 Tomcat 展示友好的错误信息页面
  8. java tomcat 日志分析工具_设计一个Tomcat访问日志分析工具
  9. 股票实时行情数据接口编译
  10. HTML+CSS(part 1)
  11. 3.VM虚拟机网络设置--仅主机模式
  12. 字节跳动否认完成支付牌照收购 或是基于央行批准的不确定性
  13. APIO 2017 考拉的游戏 题解
  14. 逃跑吧少年服务器维护中怎么回事,逃跑吧少年7月6日更新维护公告
  15. 时间戳转化时间,解决总是1970年
  16. 如何查看网页操作中调用的js方法
  17. 环境土壤物理模型 HYDRUS1D/2D/3D 应用
  18. 用代码送上 Happy New Year
  19. Xshell配色方案说明
  20. 信贷--------

热门文章

  1. 提示不支持IE6的脚本
  2. 《霸王别姬》经典台词
  3. 批处理(bat)没有后缀的文件怎么复制?
  4. Js对接口数据归类整理
  5. vue - 开发环境构建
  6. linux中lsattr命令,Linux命令(16)——chattr与lsattr命令
  7. php disable-ipv6,強迫 PHP Curl 使用 IPv4 , 忽略 IPv6
  8. python识别中文中的名字地点时间_python中判断时间间隔的问题
  9. 计算机2级文档试题,计算机二级考试word操作题真题
  10. SQL:postgresql查询结果加一个自定义的列