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
  • 相关阅读:
    document.getElementById("mytxt").style.left=""style.left在IE的FF中注意
    asp.net 用户控件中 使用相对路径的解决方法 图片路径问题(用户控件、图片路径) ,ResolveUrl
    探索 Block (一) (手把手讲解Block 底层实现原理)
    iOS 多线程开发 (概念与API简介)
    iOS 性能小点
    iOS runtime (二)(runtime学习之AutoCoding源码分析)
    探索 NSRunLoop (二)(NSRunLoop 自己动手实现SimpleRunLoop)
    iOS NSNotificationCenter (自己实现一个通知中心XMCNotificationCenter)
    iOS runtime (三)(runtime学习之YYModel源码分析)
    iOS runtime(一)(runtime 分析理解)
  • 原文地址:https://www.cnblogs.com/ourfutr2330/p/5665080.html
Copyright © 2011-2022 走看看