bzoj 2013 华容道

比较难的题单独拉出来讲咯

华容道

描述

小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次。于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间。

小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的:

  1. 在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的;
  2. 有些棋子是固定的,有些棋子则是可以移动的;
  3. 任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。 游戏的目的是把某个指定位置可以活动的棋子移动到目标位置。

给定一个棋盘,游戏可以玩 q 次,当然,每次棋盘上固定的格子是不会变的,但是棋盘上空白的格子的初始位置、指定的可移动的棋子的初始位置和目标位置却可能不同。第 i 次玩的时候,空白的格子在第 EXiEX_iEX?i?? 行第 EYiEY_iEY?i?? 列,指定的可移动棋子的初始位置为第 SXiSX_iSX?i?? 行第 SYiSY_iSY?i?? 列,目标位置为第 TXiTX_iTX?i?? 行第 TYiTY_iTY?i?? 列。

假设小 B 每秒钟能进行一次移动棋子的操作,而其他操作的时间都可以忽略不计。请你告诉小 B 每一次游戏所需要的最少时间,或者告诉他不可能完成游戏。

格式

输入格式

第一行有 3 个整数,每两个整数之间用一个空格隔开,依次表示 n、m 和 q;

接下来的 n 行描述一个 n*m 的棋盘,每行有 m 个整数,每两个整数之间用一个空格隔开,每个整数描述棋盘上一个格子的状态,0 表示该格子上的棋子是固定的,1 表示该格子上的棋子可以移动或者该格子是空白的。

接下来的 q 行,每行包含 6 个整数依次是 EXiEX_iEX?i??、EYiEY_iEY?i??、SXiSX_iSX?i??、SYiSY_iSY?i??、TXiTX_iTX?i??、TYiTY_iTY?i??,每两个整数之间用一个空格隔开,表示每次游戏空白格子的位置,指定棋子的初始位置和目标位置。

输出格式

输出有 q 行,每行包含 1 个整数,表示每次游戏所需要的最少时间,如果某次游戏无法完成目标则输出?1。

样例1

样例输入1

3 4 2
0 1 1 1
0 1 1 0
0 1 0 0
3 2 1 2 2 2
1 2 2 2 3 2

Copy

样例输出1

2
-1

Copy

限制

每个测试点1s。

提示

###样例说明

棋盘上划叉的格子是固定的,红色格子是目标位置,圆圈表示棋子,其中绿色圆圈表示目标棋子。

  1. 第一次游戏,空白格子的初始位置是 (3, 2)(图中空白所示),游戏的目标是将初始位置在(1, 2)上的棋子(图中绿色圆圈所代表的棋子)移动到目标位置(2, 2)(图中红色的格子)上。

    移动过程如下:

  2. 第二次游戏,空白格子的初始位置是(1, 2)(图中空白所示),游戏的目标是将初始位置在(2, 2)上的棋子(图中绿色圆圈所示)移动到目标位置 (3, 2)上。

    要将指定块移入目标位置,必须先将空白块移入目标位置,空白块要移动到目标位置,必然是从位置(2,2)上与当前图中目标位置上的棋子交换位置,之后能与空白块交换位置的只有当前图中目标位置上的那个棋子,因此目标棋子永远无法走到它的目标位置,游戏无法完成。

###数据范围

对于 30%的数据,1 ≤ n, m ≤ 10,q = 1;
对于 60%的数据,1 ≤ n, m ≤ 30,q ≤ 10;
对于 100%的数据,1 ≤ n, m ≤ 30,q ≤ 500。

这个确实比较难 预处理没有想到 推荐一波 比较好的博客

存一波代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int M=55,inf=0x3f3f3f3f;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<‘0‘||c>‘9‘){if(c==‘-‘) f=-1; c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){ans=ans*10+(c-‘0‘); c=getchar();}
    return ans*f;
}
int n,m,p,ex,ey,sx,sy,tx,ty,ans;
struct node{int x,y,k;}e1,e2;
int map[M][M],step[M][M],dis[M][M][5],mov[M][M][5][5];
bool vis[M][M],f[M][M][5];
node modify(node s,int k){
    if(k==1) s.x--;
    if(k==2) s.y--;
    if(k==3) s.y++;
    if(k==4) s.x++;
    return s;
}
int bfs(node s,node T){
    node now,z;
    memset(step,0x3f,sizeof(step));
    memset(vis,0,sizeof(vis));
    queue<node>q;
    q.push(s);
    step[s.x][s.y]=0; vis[s.x][s.y]=1;
    while(!q.empty()&&!vis[T.x][T.y]){
        z=q.front(); q.pop();
        for(int k=1;k<=4;k++){
            now=modify(z,k);
            if(!vis[now.x][now.y]&&map[now.x][now.y]){
                vis[now.x][now.y]=1;
                step[now.x][now.y]=step[z.x][z.y]+1;
                q.push(now);
            }
        }
    }
    return step[T.x][T.y];
}
void prepare(){
    memset(mov,0x3f,sizeof(mov));
    for(int i=1;i<=n;i++){
     for(int j=1;j<=m;j++){
        if(!map[i][j]) continue;
        map[i][j]=0;
        for(int k=1;k<=4;k++){
            for(int l=1;l<=4;l++){
                if(l<k){mov[i][j][k][l]=mov[i][j][l][k];continue;}
                e1=modify((node){i,j,k},k); e2=modify((node){i,j,l},l);
                if(!map[e1.x][e1.y]||!map[e2.x][e2.y]) continue;
                mov[i][j][k][l]=bfs(e1,e2)+1;
            }
        }
        map[i][j]=1;
     }
    }
}
void spfa(node s,node T){
    ans=inf;
    if(s.x==T.x&&s.y==T.y){ans=0; return ;}
    if(!map[s.x][s.y]||!map[T.x][T.y]) return;
    node z,now;
    memset(dis,0x3f,sizeof(dis));
    memset(f,0,sizeof(f));
    queue<node>q;
    map[s.x][s.y]=0;
    for(int i=1;i<=4;i++){
        q.push((node){s.x,s.y,i});
        f[s.x][s.y][i]=1;
        dis[s.x][s.y][i]=bfs((node){ex,ey,0},modify(s,i));
    }
    map[s.x][s.y]=1;
    while(!q.empty()){
        z=q.front(); q.pop();
        f[z.x][z.y][z.k]=0;
        for(int i=1;i<=4;i++){
            now=modify(z,i); now.k=5-i;
            if(dis[now.x][now.y][now.k]>dis[z.x][z.y][z.k]+mov[z.x][z.y][z.k][i]){
                dis[now.x][now.y][now.k]=dis[z.x][z.y][z.k]+mov[z.x][z.y][z.k][i];
                if(!f[now.x][now.y][now.k]) q.push(now),f[now.x][now.y][now.k]=1;
            }
        }
    }
    for(int i=1;i<=4;i++) ans=min(ans,dis[T.x][T.y][i]);

}
int main()
{
    n=read(); m=read(); p=read();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            map[i][j]=read();
    prepare();
    for(int i=1;i<=p;i++){
        ex=read();ey=read(); sx=read();sy=read(); tx=read();ty=read();
        spfa((node){sx,sy,0},(node){tx,ty,0});
        if(ans==inf) printf("-1\n");
        else printf("%d\n",ans);
    }
    return 0;
}

时间: 2024-11-17 16:31:31

bzoj 2013 华容道的相关文章

bzoj 2013

http://www.lydsy.com/JudgeOnline/problem.php?id=2013 最初看这个题的时候,以为神题不可做,然后去找yzjc..然后做法过于简单了(' '      ) 先排个序.假设我们已经将前i个砖块有一个合法的方案,那么加入第i + 1个砖块的时候可加入的位置都是一定的,都为在1 ~ i 中 > l[i +1] - D 的砖块的个数,因为插在中间的时候由于保证了所有已经加入的砖块的长度都小于i + 1块,所以只和上一块有关,所以只要满足上面那个式子就可以了

bzoj 2013 上升计数

题意: 给一个数集和一个数d,问满足下列要求的排列数(相同的数要区分):  a[i]+d>=a[i+1] ( i in [1,n) ) 因为数的给出顺序不重要,所以先排序,假如我们已经解决了前i个数的答案,考虑前i+1个数,即我们可以将第i+1个数放在哪,然后发现对于前i个数的每一种方案,我们都可以选择将第i+1个数放在大于等于它-d的数的上面,从而形成一种新的方案(当然直接可以放在地上),然后就完了. 收获: 1. 对于不重要的东西(如原序列的顺序),可以直接舍弃 2. 减小问题规模,发现小规

noip 2013 华容道

/*双向bfs (得分和单项的一样多....)70*/ #include<iostream> #include<cstdio> #include<cstring> #include<queue> #define maxn 35 #define maxm 810010 using namespace std; int n,m,q,g[maxn][maxn]; int X,Y,sx,sy,ex,ey,falg,vis[maxn][maxn]; int xx[4]

BZOJ 3170: [Tjoi 2013]松鼠聚会( sort )

题目的距离为max(|x1-x2|, |y1-y2|) (切比雪夫距离). 切比雪夫距离(x, y)->曼哈顿距离((x+y)/2, (x-y)/2) (曼哈顿(x, y)->切比雪夫(x+y, x-y)). 转成Manhattan distance后排序前缀和维护即可. -------------------------------------------------------------------------- #include<cstdio> #include<cs

【CodeVS 3290】【NOIP 2013】华容道

http://codevs.cn/problem/3290/ 据说2013年的noip非常难,但Purpleslz学长还是AK了.能A掉这道题真心orz. 设状态$(i,j,k)$表示目标棋子在$(i,j)$这个位置,空格在紧贴着目标棋子的$k$方向,$0≤k<4$. 因为目标棋子要移动,空格肯定在它旁边.往空格的方向走一步,空格便出现在它另一边.对于这两个状态连边,边权为1. 为了使目标棋子向某一方向移动,需要目标棋子不动,空格从紧贴着目标棋子的某一方向移动到紧贴着目标棋子的另一个方向.对于固

[BZOJ 3238] [AHOI 2013] 差异

题目链接:BZOJ - 3238 题目分析 显然,这道题就是求任意两个后缀之间的LCP的和,这与后缀数组的联系十分明显. 求出后缀数组后,求出字典序相邻两个后缀的LCP,即 Height 数组. 那么我们可以用这个 Height 数组求出所有后缀之间 LCP 的和. 我们用 f[i] 表示字典序第 i 的后缀与字典序在 i 之后的所有后缀的 LCP 的和. 我们知道,两个后缀的 LCP 为 Height 数组中这两个后缀之间的最小值. 我们从最后向前推 i ,用一个单调栈维护后面的 Height

BZOJ 3238 AHOI 2013 差异 后缀数组+单调栈

题目大意: 思路:一看各种后缀那就是后缀数组没跑了. 求出sa,height之后就可以乱搞了.对于height数组中的一个值,height[i]来说,这个值能够作为lcp值的作用域只在左边第一个比他小的位置到右边第一个比他小的位置.这个东西很明显可以倍增RMQ+二分/单调栈. 之后就是数学题了 Σlen[Ti] + len[Tj] = (len + 1) * len * (len - 1),之后吧所有求出来的Σ2 * lcp(Ti,Tj)减掉就是答案. 记得答案开long long CODE:

BZOJ 3170 [Tjoi 2013]松鼠聚会

题目描述 有N个小松鼠,它们的家用一个点x,y表示,两个点的距离定义为:点(x,y)和它周围的8个点即上下左右四个点和对角的四个点,距离为1.现在N个松鼠要走到一个松鼠家去,求走过的最短距离. 输入 第一行给出数字N,表示有多少只小松鼠.0<=N<=10^5下面N行,每行给出x,y表示其家的坐标.-10^9<=x,y<=10^9 输出 表示为了聚会走的路程和最小为多少. 样例输入 6 -4 -1 -1 -2 2 -4 0 2 0 3 5 -2 样例输出 20 解题思路 新学了一个姿

BZOJ 3144 HNOI 2013 切糕 最小割

题目大意:给出一个三维的点阵,没个点都有可能被切割,代价就是这个点的权值.相邻的切割点的高度差不能超过D,问最小的花费使得上下分开. 思路:很裸的最小割模型,很神的建图. S->第一层的点,f:INF 所有点->它下面的点,f:INF 一个点的入->一个点的出,f:val[i] (i,j,k) - > (i - d,j,k),f:INF 最下面一层的点->T:f:INF 然后跑最小割就是答案. 为什么见:http://www.cnblogs.com/zyfzyf/p/4182