[noip2013]华容道(bfs+spfa)
来源:互联网 发布:哈登第四周场均数据 编辑:程序博客网 时间:2024/05/14 09:19
题目:
我是超链接
题解:
这种想着办法优化的题。。。
70pts:暴力——把空白格子随意乱移,遇到目标格子就换个位置,bfs就ok
100pts:bfs+spfa
很明确的是要想把格子S移到目标位置T,首先得把白格子E移到S的旁边,在通过一系列的操作使格子S到达T
格子S想要走到与它相邻的k方向(left,right,up,down)上的格子,必须先把E格子通过w的花费移到那里,然后在用1的花费使S走到那 里,总花费为w+1,由于从一个格子向相邻方向上走一步的花费要多次使用,因此我们把它预处理成数组move[x][y][k][h],表示这个棋子(x,y),白格子在k方向上,使棋子走到h方向上相邻的格子的最少花费,这个可以用BFS预处理
有了这么多东西,能不能用BFS做呢?不行。从一个点走到相邻的节点的花费不一定是1,而且还受白格子所在方向的影响,所以就不再设状态为(x,y),而是(x,y,k),k表示白格子的方向,dist[x][y][k]存储走到这个状态的最小步数。很明显,从一个格子向h方向走的最小代价就是move[x][y][k][h],很明显这个状态只能转移到(x,y,other(h)),other(h)表示和h相反的方向,比如你向右走完一次,白格子一定在这个格子的左侧。
现在已经构建了一个又状态(x,y,k)构成的一张图,边权也已经算出来了,因此想要从出发点找一条到结束点的最短路径,可以用SPFA
move[i][j][k][l]表示棋子在i,j时,白格子在ta的k方向上,使棋子走到l方向的最少花费
dis[i][j][k]表示棋子在i,j白格子在k方向的最小花费
代码:
70pts
#include <cstdio>#include <queue>#include <cstring>using namespace std;int EXi,EYi,SXi,SYi,TXi,TYi,n,m;bool a[35][35],vis[35][35][35][35];struct hh{int x,y,a,b,bs;};const int c[4][2]={{1,0},{0,1},{-1,0},{0,-1}};int bfs(){ memset(vis,0,sizeof(vis)); queue<hh>q; q.push((hh){EXi,EYi,SXi,SYi,0}); vis[EXi][EYi][SXi][SYi]=1; while (!q.empty()) { hh now=q.front(); q.pop(); if (now.a==TXi && now.b==TYi) return now.bs; for (int i=0;i<=3;i++) { int xx=now.x+c[i][0],yy=now.y+c[i][1],aa=now.a,bb=now.b; if (xx<1 || yy<1 || xx>n || yy>m || !a[xx][yy]) continue; if (xx==now.a && yy==now.b){aa=now.x; bb=now.y;} if (vis[xx][yy][aa][bb]) continue; vis[xx][yy][aa][bb]=1; q.push((hh){xx,yy,aa,bb,now.bs+1}); } } return -1;}int main(){ int i,q,j; scanf("%d%d%d",&n,&m,&q); for (i=1;i<=n;i++) for (j=1;j<=m;j++) scanf("%d",&a[i][j]); while (q--) { scanf("%d%d%d%d%d%d",&EXi,&EYi,&SXi,&SYi,&TXi,&TYi); if (SXi==TXi && SYi==TYi) {printf("0\n");continue;} printf("%d\n",bfs()); }}
100pts
#include <cstdio>#include <queue>#include <cstring>#define up 1#define down 2#define left 3#define right 4#define INF 1e9using namespace std;struct point{int x,y;};struct hh{int x,y,k;};int EXi,EYi,SXi,SYi,TXi,TYi,n,m,deep[35][35],move[35][35][5][5],dis[35][35][5];const int other[5]={0,2,1,4,3};bool a[35][35],viv[35][35],vis[35][35][5];point where(point x,int fx){ if (fx==up) x.x--; if (fx==down) x.x++; if (fx==left) x.y--; if (fx==right) x.y++; return x;}int bfs(point x,point y){ memset(deep,0x7f,sizeof(deep)); memset(viv,0,sizeof(viv)); queue<point>q; q.push(x); deep[x.x][x.y]=0; viv[x.x][x.y]=1; point now; while (!q.empty()) { now=q.front(); q.pop(); if (now.x==y.x && now.y==y.y) break; for (int i=1;i<=4;i++) { point wo=where(now,i); int xx=wo.x,yy=wo.y; if (xx<1 || yy<1 || xx>n || yy>m || !a[xx][yy]) continue; if (viv[xx][yy]) continue; viv[xx][yy]=1;deep[xx][yy]=deep[now.x][now.y]+1; q.push((point){xx,yy}); } } return deep[y.x][y.y];}void init()//move[i][j][k][l]表示棋子在i,j时,白格子在ta的k方向上,使棋子走到l方向的最少花费 { int i,j,k,l; for (i=1;i<=n;i++) for (j=1;j<=m;j++) if (a[i][j]) { a[i][j]=0;//这个目标格子的位置不能经过 for (k=1;k<=4;k++) for (l=1;l<=4;l++) { if (l<k) {move[i][j][k][l]=move[i][j][l][k]; continue;} point t1=where((point){i,j},k),t2=where((point){i,j},l); if (!a[t1.x][t1.y] || !a[t2.x][t2.y]) continue; move[i][j][k][l]=bfs(t1,t2)+1; } a[i][j]=1; }}int spfa(point x,point y)//dis[i][j][k]表示棋子在i,j白格子在k方向的最小花费 { memset(vis,0,sizeof(vis)); memset(dis,0x7f,sizeof(dis)); queue<hh>q; a[y.x][y.y]=0; for (int i=1;i<=4;i++) { int lj=bfs(x,where(y,i)); if (lj<INF) dis[y.x][y.y][i]=lj,q.push((hh){y.x,y.y,i}),vis[y.x][y.y][i]=1; } a[y.x][y.y]=1; while (!q.empty()) { hh now=q.front(); q.pop(); vis[now.x][now.y][now.k]=0; for (int i=1;i<=4;i++) { point to=where((point){now.x,now.y},i); if (to.x<1 || to.y<1 || to.x>n || to.y>m || !a[to.x][to.y]) continue; if (dis[now.x][now.y][now.k]+move[now.x][now.y][now.k][i]<dis[to.x][to.y][other[i]]) { dis[to.x][to.y][other[i]]=dis[now.x][now.y][now.k]+move[now.x][now.y][now.k][i]; if (!vis[to.x][to.y][other[i]]) vis[to.x][to.y][other[i]]=1,q.push((hh){to.x,to.y,other[i]}); } } } int ans=INF+50; for (int i=1;i<=4;i++) ans=min(ans,dis[TXi][TYi][i]); if (ans>INF) return -1; return ans;}int main(){ int i,q,j; scanf("%d%d%d",&n,&m,&q); for (i=1;i<=n;i++) for (j=1;j<=m;j++) scanf("%d",&a[i][j]); init(); while (q--) { scanf("%d%d%d%d%d%d",&EXi,&EYi,&SXi,&SYi,&TXi,&TYi); if (SXi==TXi && SYi==TYi) {printf("0\n");continue;} printf("%d\n",spfa((point){EXi,EYi},(point){SXi,SYi})); }}
后方吐槽:这正解好烦啊啊啊啊啊啊
- noip2013 华容道 (bfs+spfa)
- [noip2013]华容道(bfs+spfa)
- NOIP2013 华容道 [spfa+bfs]
- 【NOIP2013】华容道 SPFA+BFS预处理
- NOIP2013 DAY2 T3 华容道(PUZZLE) BFS+SPFA
- 【NOIP2013提高组T6】华容道-BFS+SPFA
- NOIP2013 华容道 (BFS,最短路)
- noip2013 华容道 bfs+建图
- 【NOIP2013】华容道 最短路优化搜索(spfa)
- 华容道 洛谷1979 bfs+spfa
- 【最短路】【bfs】[NOIP2013] codevs3290 华容道
- 洛谷 1979 华容道 [NOIP2013] bfs 50分
- NOIP2013 华容道(极难脑洞题)
- [NOIP2013]华容道
- NOIP2013华容道
- NOIP2013华容道
- NOIP2013 华容道
- noip2013华容道
- javascript 引用类型console.log调试 技巧
- elasticsearch分词聚合查询demo
- 【BZOJ4196】【NOI2015】软件包管理器(树链剖分,线段树)
- HTML5中js控制video视频和分段播放
- centos 7 linux 安装与卸载 jdk 7
- [noip2013]华容道(bfs+spfa)
- 提高代码可读性的10个技巧
- 政府安全资讯精选 2017年第十一期 英国未来可能向社交媒体网站征收网络安全税;“一法一决定”网络安全执法检查深入深圳、重庆、黑龙江等地
- angular+表格追加
- 随记——String和ArrayList一些问题。
- AtomicInteger类的理解与使用
- maven--4.概念(坐标、依赖)
- MySql远程连接-------redis实现session单点登录时数据库连接报错
- AngularJs实现 每列排序,输入查找、插入升序降序图标