zoukankan      html  css  js  c++  java
  • [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
    ",bfs(Status(e1,e2,c1,c2),d1,d2));
            else printf("-1
    ");
            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 node
        g[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
    ",work());
        return 0;
    }
    View Code
  • 相关阅读:
    CentOS6.5配置网络
    php curl 总结
    laravel-5-doctrine-2 教程
    DOS 总结
    Centos如何通过yum安装php7
    sql with 写法
    php 汉字转拼音函数
    MYSQL 升序排序但值为0的排最后
    zookeeper基础知识
    初识redis
  • 原文地址:https://www.cnblogs.com/ourfutr2330/p/5665080.html
Copyright © 2011-2022 走看看