[noip2013][codevs3290]华容道 bfs+spfa

const
        u:array[1..4] of integer=(-1,0,1,0);
        v:array[1..4] of integer=(0,1,0,-1);
        oo=100000000;
type node=record
      x,y,cs,l:longint;
      end;

var
        ft:text;
        n,m,q,ii,i,i1,j1,j,l,w,x,y,x1,y1,x2,y2,x3,y3,es,ey,wei,tou,kx,ky,ans:longint;
        r:array[0..5000000] of node;
        aa,a,fb,fb2:array[0..31,0..31] of longint;
        ff,z,z2:array[0..31,0..31,1..4] of longint;
        f:array[0..31,0..31,1..4,1..4] of longint;

        procedure bfs(x,y:longint);
        var i,x1,y1:longint;
        begin
                wei:=1;
                tou:=0;
                r[wei].x:=x;
                r[wei].y:=y;
                r[wei].cs:=fb[x,y];
                while tou<wei do
                begin
                        inc(tou);
                        for i:=1 to 4 do
                        begin
                                x1:=r[tou].x+u[i];
                                y1:=r[tou].y+v[i];
                                if (a[x1,y1]=1)and(r[tou].cs+1<fb[x1,y1]) then
                                begin
                                        inc(wei);
                                        r[wei].x:=x1;
                                        r[wei].y:=y1;
                                        r[wei].cs:=r[tou].cs+1;
                                        fb[x1,y1]:=r[wei].cs;
                                end;
                        end;
                end;
        end;

        begin
                readln(n,m,q);
                for i:=1 to n do
                begin
                        for j:=1 to m do
                        read(a[i,j]);
                        readln;
                end;

                aa:=a;
                for i:=1 to n do
                for j:=1 to m do
                begin
                        fb2[i,j]:=oo;
                        for l:=1 to 4 do
                        begin
                                z2[i,j,l]:=oo;
                                for w:=1 to 4 do f[i,j,l,w]:=oo;
                        end;
                end;

                for i:=1 to n do
                for j:=1 to m do
                if a[i,j]=1 then
                for l:=1 to 4 do
                begin
                        x:=i+u[l];
                        y:=j+v[l];
                        if (x>0)and(x<n+1)and(y>0)and(y<m+1)and(a[x,y]=1) then
                        begin
                                a[x,y]:=0;
                                fb:=fb2;
                                fb[i,j]:=1;
                                bfs(i,j);
                                for w:=1 to 4 do
                                begin
                                        x1:=x+u[w];
                                        y1:=y+v[w];
                                        if (x1>0)and(x1<n+1)and(y1>0)and(y1<m+1)and(fb[x1,y1]<oo) then
                                        begin
                                                f[i,j,l,w]:=fb[x1,y1];
                                        end;
                                end;
                                a[x,y]:=1;
                        end;
                end;

        for ii:=1 to q do
        begin
                read(kx,ky,x,y,es,ey);
                if (x=es)and(y=ey) then
                begin
                        writeln(0);
                        continue;
                end;
                fb:=fb2;
                a[x,y]:=0;
                fb[kx,ky]:=0;
                bfs(kx,ky);
                wei:=0;
                z:=z2;
                fillchar(ff,sizeof(ff),0);
                for j:=1 to 4 do
                begin
                        x1:=x+u[j];
                        y1:=y+v[j];
                        if (x1>0)and(x1<n+1)and(y1>0)and(y1<m+1)and(fb[x1,y1]<oo) then
                        begin
                        inc(wei);
                        r[wei].x:=x;
                        r[wei].y:=y;
                        r[wei].l:=j;
                        z[x,y,j]:=fb[x1,y1];
                        ff[x,y,j]:=1;
                        end;
                end;

                tou:=0;
                while tou<wei do
                begin
                        inc(tou);
                        for i:=1 to 4 do
                        begin
                        x2:=r[tou].x;
                        y2:=r[tou].y;
                        x1:=x2+u[r[tou].l]+u[i];
                        y1:=y2+v[r[tou].l]+v[i];
                        x3:=x2+u[r[tou].l];
                        y3:=y2+v[r[tou].l];
                        if (f[x2,y2,r[tou].l,i]<>oo)and(z[x3,y3,i]>z[x2,y2,r[tou].l]+f[x2,y2,r[tou].l,i]) then
                        begin
                                z[x3,y3,i]:=z[x2,y2,r[tou].l]+f[x2,y2,r[tou].l,i];
                                if ff[x3,y3,i]=0 then
                                begin
                                ff[x3,y3,i]:=1;
                                inc(wei);
                                r[wei].x:=x3;
                                r[wei].y:=y3;
                                r[wei].l:=i;
                                end;
                        end;
                        end;

                        ff[r[tou].x,r[tou].y,r[tou].l]:=0;
                end;

                ans:=oo;
                for i:=1 to 4 do
                if z[es,ey,i]<ans then ans:=z[es,ey,i];
                if ans=oo then writeln(-1)
                else writeln(ans);
                a[x,y]:=1;
                end;
        end.

因为对棋子的移动最终对应着对空格的移动,而空格的初始位置(非起始情况)一定是在目标棋子的上下左右的。

这样我们把空格先准备好,然后移动一下棋子,这种操作的代价很容易发现是常数。因此可以使用最短路。方法是把每个棋子一分为四,上下左右,[一个棋 子的左边]就代表了空格的初始位置在这个棋子的左边,即它前一次是从左边移过来的。每个棋子的每一边可以建立于上面棋子的下边,下面棋子的上边等的联系 (用一个有向图来存储),并存储价值。

最后还有一个小问题,就是每次的q的空白位置不是在目标棋子的上下左右。这时候选择目标棋子的一类,并且修改其与周遭棋子联系的边权,然后做最短路,然后记得要改回去。

时间: 2024-12-19 09:50:17

[noip2013][codevs3290]华容道 bfs+spfa的相关文章

【NOIP2013】华容道

P1675 - [NOIP2013]华容道 Description Input Output Sample Input Sample Output Hint 暴力:BFS. 搜索空白的格子往四周走. 队列里面记录空格的位置和目标块的位置和步数,并且标记这个状态不能重复走. 这样搞好像有80分. 正解:BFS+SPFA. 要使某个块走到特定的点,首先要使空格移到这个块的边上. 然后再不断地移这个块. 所以,先要BFS求出空白块移到这个块需要多少步. 然后空白块就在这个块边上了. 考虑到要不停的移这

NOIP2013 提高组day2 3 华容道 BFS

描述 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间. 小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的: 在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的: 有些棋子是固定的,有些棋子则是可以移动的: 任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白

JZYZOJ1442 [noip2013]华容道 bfs 最短路 剪枝

http://172.20.6.3/Problem_Show.asp?id=1442 想到最短路的简直神了,如果我写我大概只能写一个30分的bfs. 从数据范围可以看出思路是bfs剪枝,但这里的剪枝是通过最短路的预处理实现的. 设需要移动的格子为a格子. 对求最小移动数有意义的移动只有两种,一种是空白格子的移动,一种是a格子移动到空白格子里. 可以得知要把空白格子移动到a格子旁边然后对a格子进行移动. 那么我们有了每次查找时进行的预处理1:求空白格子到a格子四周格子的最短路. 在模拟移动的过程中

Luogu1979【NOIP2013】 华容道

题目描述 [问题描述] 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面, 华容道是否根本就无法完成,如果能完成, 最少需要多少时间. 小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的: 在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的: 有些棋子是固定的,有些棋子则是可以移动的: 任何与空白的格子相邻(有公共的边)的格子上

【模板】负环(spfa)

洛谷——P3385 [模板]负环 题目描述 暴力枚举/SPFA/Bellman-ford/奇怪的贪心/超神搜索 输入输出格式 输入格式: 第一行一个正整数T表示数据组数,对于每组数据: 第一行两个正整数N M,表示图有N个顶点,M条边 接下来M行,每行三个整数a b w,表示a->b有一条权值为w的边(若w<0则为单向,否则双向) 输出格式: 共T行.对于每组数据,存在负环则输出一行"YE5"(不含引号),否则输出一行"N0"(不含引号). 输入输出样例

codevs 3290 华容道

HAHAHA BFS+SPFA. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define maxn 35 #define maxv 100500 #define maxe 400500 #define inf 100000007 using namespace std; struct edge { int v

【枚举】【SPFA】Urozero Autumn Training Camp 2016 Day 5: NWERC-2016 Problem I. Iron and Coal

那个人派出的队伍的行走的路径一定前半程是重合的,后半程分叉开来. 于是预处理每个点离1号点的最短路,到最近的铁的最短路,到最近的煤的最短路.(三次BFS / SPFA)然后枚举分岔点,尝试更新答案即可. #include<cstdio> #include<queue> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; queue<int>

noip2012~2015刷题小记录

2012d1t1 密码 模拟题 1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<cmath> 5 #include<iostream> 6 #include<algorithm> 7 #include<set> 8 #include<queue> 9 #include<vector> 10 using nam

[题解+总结]NOIP历年题目分析

1.前言 迎接NOIP的到来...在这段闲暇时间,决定刷刷水题.这里只是作非常简单的一些总结. 2.NOIP2014 <1> 生活大爆炸之石头剪刀布(模拟) 这是一道考你会不会编程的题目...方法有很多,预处理输赢矩阵,或者一大堆if什么的乱搞就行了. <2> 联合权值(搜索) 简单的树上求解问题,由于只需要长度为2的链,只要能够清楚地分析出各种情况,一遍DFS直接出来:自身节点与祖父节点有一对:自身节点与兄弟节点有若干对.在计算权值的时候存在一个优化,即如果每次得到一对之后就计算