codevs 3290 noip 2013 Day2 T3华容道

13 篇文章 0 订阅
13 篇文章 3 订阅

唔马上要考noip了 泪目。希望rp++。

莫名被archer圈粉。

今天终于搞定这道题了 呼。。。

所以orz当年4(+3)神犇。

题目描述 Description
小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次。于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间。
小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的:

在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的;
有些棋子是固定的,有些棋子则是可以移动的;
任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。 游戏的目的是把某个指定位置可以活动的棋子移动到目标位置。
给定一个棋盘,游戏可以玩 q 次,当然,每次棋盘上固定的格子是不会变的,但是棋盘上空白的格子的初始位置、指定的可移动的棋子的初始位置和目标位置却可能不同。第 i 次玩的时候,空白的格子在第 EX_i 行第 EY_i 列,指定的可移动棋子的初始位置为第 SX_i 行第 SY_i 列,目标位置为第 TX_i 行第 TY_i 列。
假设小 B 每秒钟能进行一次移动棋子的操作,而其他操作的时间都可以忽略不计。请你告诉小 B 每一次游戏所需要的最少时间,或者告诉他不可能完成游戏。

输入描述 Input Description
第一行有 3 个整数,每两个整数之间用一个空格隔开,依次表示 n、m 和 q;
接下来的 n 行描述一个 n*m 的棋盘,每行有 m 个整数,每两个整数之间用一个空格隔开,每个整数描述棋盘上一个格子的状态,0 表示该格子上的棋子是固定的,1 表示该格子上的棋子可以移动或者该格子是空白的。
接下来的 q 行,每行包含 6 个整数依次是 EX_i、EY_i、SX_i、SY_i、TX_i、TY_i,每两个整数之间用一个空格隔开,表示每次游戏空白格子的位置,指定棋子的初始位置和目标位置。

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

样例输入 Sample Input
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

样例输出 Sample Output
2
-1

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

60%很好说吧。bfs就可以。。直接上代码了!【得了65 是要闹哪样】

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
//by mars_ch
using namespace std;
struct data
{
    int x,y;
    int kx,ky;
    int dis;
}a;
int n,m,k;
int ex,ey,sx,sy,tx,ty;
int map[30][30];
int vis[30][30][30][30];
int dx[5]={1,-1,0,0};
int dy[5]={0,0,1,-1};
queue<data> q;
void bfs()
{
    while(!q.empty()) q.pop();
    memset(vis,0,sizeof(vis));
    data t;
    t.x=sx,t.y=sy;
    t.kx=tx,t.ky=ty;
    t.dis=0;
    if(t.x == ex && t.y==ey){
        printf("0\n");
        return;
    } 
    vis[sx][sy][tx][ty]=1;
    q.push(t);
    while(!q.empty())
    {
        data v=q.front();
        q.pop();

        for(int i=0;i<4;i++)
        {
            int nx=v.x,ny=v.y;
            int bx=v.kx+dx[i],by=v.ky+dy[i];;
            if(bx == nx && by == ny)
            {
                nx=v.kx,ny=v.ky;
            }
            if(nx<=n && ny<=m && nx>0 && ny>0 && bx<=n && bx>0 && by<=m && by>0 && map[nx][ny]==1 && map[bx][by] == 1 &&!vis[nx][ny][bx][by])
            {
                vis[nx][ny][bx][by]=1;
                data u;
                u.x=nx,u.y=ny,u.kx=bx,u.ky=by;
                u.dis=v.dis+1;
                if(nx == ex && ny == ey)
                {
                    printf("%d\n",u.dis);
                    return;
                }
                q.push(u);
            }
        }
    }
    printf("-1\n");
    return;
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&map[i][j]);
        }
    }
    while(k--)
    {
        scanf("%d%d%d%d%d%d",&tx,&ty,&sx,&sy,&ex,&ey);
        bfs();
    }
    return 0;
}

然后来说正解:
好吧,又看了正解yy了很久。
然后网上的代码都好繁琐啊 泪目。。

所以 根据60分算法观察,我们搜索到了许多并不会移动的状态。并且每次询问的 棋盘式固定的也就是可移动的棋子是固定的。

我们又拥有2种操作:
1.将空白格子移至目标棋子想要前进的方向。

2.空白格子和目标棋子相邻,交换【一起移动】

对于每个合法点A(x,y),枚举一个E(ex,ey)表示相邻的空格的位置,和一个T(tx,ty)表示要把目标棋子从这个格子移向的位置【方向】。

这里写图片描述

所以如果将所有的状态都处理出来,那么每个格子到每个格子就先定了。

所以 我们只需要建边跑一边spfa就OK了!

注意状态时3维的啦~

上代码

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define inf 1000000007
//by mars_ch
using namespace std;
int n,m,k;
int ex,ey,sx,sy,tx,ty;
int map[35][35],ha[32][35][5],dis[35][35],d[5005],inq[5005];
int dx[5]={1,-1,0,0};
int dy[5]={0,0,1,-1};
struct data
{
    int f,t,w,nxt;
}e[300005];
int first[100005],tot;
void add(int a,int b,int c)
{
    e[tot].f=a,e[tot].t=b,e[tot].w=c;
    e[tot].nxt=first[a],first[a]=tot++;
}
int bfs(int stx,int sty,int edx,int edy)
{
    if(stx == edx && sty == edy) return 0;
    queue<pair<int,int> > q;
    memset(dis,-1,sizeof(dis));
    q.push(make_pair(stx,sty));
    dis[stx][sty]=0;
    while(!q.empty())
    {
        int nx=q.front().first,ny=q.front().second;
        q.pop();
        for(int i=0;i<4;i++){
            int xx=nx+dx[i],yy=ny+dy[i];
            if(!map[xx][yy] || dis[xx][yy]!=-1)continue;
            dis[xx][yy]=dis[nx][ny]+1;
            if(xx == edx && yy==edy){
                return dis[xx][yy];
            }
            q.push(make_pair(xx,yy));
        }
    }
    return inf;
}
void pre_bfs(int x,int y)
{
    for(int i=0;i<4;i++){
        int nx=x+dx[i],ny=y+dy[i];
        if(!map[nx][ny]) continue;
        for(int j=0;j<4;j++){
            int xx=x+dx[j],yy=y+dy[j];
            if(!map[xx][yy]) continue;
            int temp=bfs(nx,ny,xx,yy);
            if(temp!=inf){
                add(ha[x][y][i],ha[xx][yy][j^1],temp+1);
            }
        }
    } 
}
int spfa(int s,int t)
{
    queue<int> q;
    for(int i=1;i<=t;i++)
    {
        d[i]=inf;
        inq[i]=0;
    }
    d[s]=0;
    q.push(s);
    inq[s]=1;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        inq[u]=0;

        for(int i=first[u];i!=-1;i=e[i].nxt)
        {
            int t=e[i].t;
            if(d[t]>d[u]+e[i].w){
                d[t]=d[u]+e[i].w;
                if(!inq[t]){
                    inq[t]=1;
                    q.push(t);
                }
            }
        }
    }
    if(d[t] == inf) return -1;
    else return d[t];

 } 
int main()
{
    int h=0;
    scanf("%d%d%d",&n,&m,&k);
    memset(first,-1,sizeof(first));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%d",&map[i][j]);
            for(int d=0;d<4;d++)
            {
                ha[i][j][d]=++h;
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(map[i][j]){
                map[i][j]=0;
                pre_bfs(i,j);
                map[i][j]=1;
            }
        }
    }
    while(k--)
    {
        scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty);
        if(sx == tx && sy==ty){
            puts("0");
            continue;
        }
        int S=++h,T=++h;
        map[sx][sy]=0;
        for(int i=0;i<4;i++)
        {
            int nx=sx+dx[i],ny=sy+dy[i];
            if(!map[nx][ny]) continue;
            int temp=bfs(ex,ey,nx,ny);
            if(temp!=inf){
                add(S,ha[sx][sy][i],temp);
            }
        }
        map[sx][sy]=1;

        for(int i=0;i<4;i++)
        {
            int nx=tx+dx[i],ny=ty+dy[i];
            if(map[nx][ny]){
                add(ha[tx][ty][i],T,0);
            }
        }
        printf("%d\n",spfa(S,T));

    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值