[NOIP2013] 华容道
初看这道题,想到纯暴力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] 华容道相关推荐
- NOIP2013 华容道
传送门 分析 暴力能拿 \(60\) ~ \(70pts\) . 具体的...以后再更吧 代码 #include <queue> #include <cstdio> #incl ...
- 刷题记录:牛客NC16536[NOIP2013]华容道
传送门:牛客 题目描述: 题目较长,此处略 这道题的难度在洛谷上达到了紫题的水准,感觉还是有难度的( 花了我几乎5个小时 ),并且在没有看题解之前,根本不知道怎么做,脑中能想到的只有感觉会被T掉的算法 ...
- noip2017考前整理(未完)
快考试了,把我以前写过的题回顾一下. Noip2007 树网的核:floyd,推出性质,暴力. Noip2008 笨小猴:模拟 Noip2008 火柴棒等式:枚举 Noip2008 传纸条:棋盘dp ...
- 语法入门*算法入门题单
作者:王清楚 链接:https://ac.nowcoder.com/discuss/817596?type=101&order=0&pos=1&page=4&chann ...
- 【新手上路】语法入门算法入门题单
作者:王清楚 链接:[新手上路]语法入门&算法入门题单_ACM竞赛_ACM/CSP/ICPC/CCPC/比赛经验/题解/资讯_牛客竞赛OJ_牛客网 来源:牛客网 介绍:本题单分为语法入门和算法 ...
- 算法初探系列5 - 广度优先搜索之状态表示
概述 上节课我们学习了在简单迷宫问题中如何使用BFS求解,这次我们来讲解一下较复杂 ~~(花里胡哨)~~ 的迷宫问题 复习+延伸(多起点BFS) 在普通bfs问题中,我们先将起点入队,然后一直从起点延 ...
- 【题解】P1979 [NOIP2013 提高组] 华容道(SPFA,BFS,常数优化)
[题解]P1979 [NOIP2013 提高组] 华容道 最近打比赛次次挂..平均每周得被至少一场比赛打击一次(这周好不容易 ABC 打的还行模拟赛又挂--)心烦意乱.写篇题解疏散一下内心的苦闷(雾) ...
- 【NOIP2013】华容道 最短路优化搜索(spfa)
华容道 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 34 Solved: 14 [Submit][Status][Web Board] Descr ...
- python华容道最短路径_SSOJ1322华容道(NOIP2013)
题目大意:在一个棋盘上,0不能做,1可以走,现在要将一个棋子移动到目标位置,移动时只能跟空格(只有一个)交换位置,至少要多少步? 题目描述 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一 ...
- P1979 [NOIP2013 提高组] 华容道
题目来源 [NOIP2013 提高组] 华容道 - 洛谷 题目考点 搜索 图论 题目 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面, ...
最新文章
- 面试:为什么 Java 线程没有Running状态?
- 支付宝能扫码闪电开发票了!人均省时3分钟
- WPF 触发器Triggers
- salesforce 零基础学习(四十二)简单文件上传下载
- 最后一个单词的长度Python解法
- 架构师之路 扩充字段_扩大您作为设计师的业务影响力的四个基础
- java web的友好页面_JavaWeb 之 由 Tomcat 展示友好的错误信息页面
- java tomcat 日志分析工具_设计一个Tomcat访问日志分析工具
- 股票实时行情数据接口编译
- HTML+CSS(part 1)
- 3.VM虚拟机网络设置--仅主机模式
- 字节跳动否认完成支付牌照收购 或是基于央行批准的不确定性
- APIO 2017 考拉的游戏 题解
- 逃跑吧少年服务器维护中怎么回事,逃跑吧少年7月6日更新维护公告
- 时间戳转化时间,解决总是1970年
- 如何查看网页操作中调用的js方法
- 环境土壤物理模型 HYDRUS1D/2D/3D 应用
- 用代码送上 Happy New Year
- Xshell配色方案说明
- 信贷--------