zoukankan      html  css  js  c++  java
  • HDU 1180 诡异的楼梯【BFS/楼梯随时间变化】

    诡异的楼梯
    Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)
    Total Submission(s): 17892 Accepted Submission(s): 4652

    Problem Description
    Hogwarts正式开学以后,Harry发现在Hogwarts里,某些楼梯并不是静止不动的,相反,他们每隔一分钟就变动一次方向.
    比如下面的例子里,一开始楼梯在竖直方向,一分钟以后它移动到了水平方向,再过一分钟它又回到了竖直方向.Harry发现对他来说很难找到能使得他最快到达目的地的路线,这时Ron(Harry最好的朋友)告诉Harry正好有一个魔法道具可以帮助他寻找这样的路线,而那个魔法道具上的咒语,正是由你纂写的.

    Input
    测试数据有多组,每组的表述如下:
    第一行有两个数,M和N,接下来是一个M行N列的地图,'*'表示障碍物,'.'表示走廊,'|'或者'-'表示一个楼梯,并且标明了它在一开始时所处的位置:'|'表示的楼梯在最开始是竖直方向,'-'表示的楼梯在一开始是水平方向.地图中还有一个'S'是起点,'T'是目标,0<=M,N<=20,地图中不会出现两个相连的梯子.Harry每秒只能停留在'.'或'S'和'T'所标记的格子内.

    Output
    只有一行,包含一个数T,表示到达目标的最短时间.
    注意:Harry只能每次走到相邻的格子而不能斜走,每移动一次恰好为一分钟,并且Harry登上楼梯并经过楼梯到达对面的整个过程只需要一分钟,Harry从来不在楼梯上停留.并且每次楼梯都恰好在Harry移动完毕以后才改变方向.

    Sample Input
    5 5
    **..T
    **..
    ..|..
    .
    .*.
    S....

    Sample Output
    7

    Hint
    Hint

    地图如下:

    Source
    Gardon-DYGG Contest 1
    【分析】:
    解题思路:看到这种类似走迷宫的题第一反应就是搜索,然而这题不只是一般的搜索那么简单,原因就是那个楼梯,走到这个楼梯的时间和位置恰当的话可以让你获得“加速”,因此利用好这个楼梯很关键。注意的是楼梯方向会变,因此走到楼梯边上时要特判一下。
    楼梯的方向要与前进的方向一致,这就牵扯到时机问题——如果恰好可以上楼梯(比如楼梯这时候的状态是竖直的,而你恰好在它下方的格子需要往上走),这时候就可以利用这个楼梯(相当于是跳了一步)。但如果状态不合适,那你无法使用这个楼梯,只能选择继续向别的方向走或者原地等待(相当于无法利用这个楼梯获得“加速”)
    【代码】:

    #include<cstdio>
    #include<string>
    #include<cstdlib>
    #include<cmath>
    #include<iostream>
    #include<cstring>
    #include<set>
    #include<queue>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<cctype>
    #include<stack>
    #include<sstream>
    #include<list>
    #include<assert.h>
    #include<bitset>
    #include<numeric>
    using namespace std;
    
    typedef long long ll;
    typedef unsigned long long ULL;
    typedef pair<int,int> P;
    const int INF = 0x3f3f3f3f;
    const ll LNF = 1e18;
    const int maxn = 1e5 + 100;
    const int maxm = 100;
    const double PI = acos(-1.0);
    const double eps = 1e-8;
    //const int dx[] = {-1,1,0,0,1,1,-1,-1};
    //const int dy[] = {0,0,1,-1,1,-1,1,-1};
    int dx[] = {-1,0,1,0};
    int dy[] = {0,1,0,-1};
    //        上/右/下/左
    const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    const int dir[6][3]={ {0,0,1},{0,0,-1},{-1,0,0},{1,0,0},{0,1,0},{0,-1,0} };
    int dir[4][2]= {{-1,0},{0,1},{1,0},{0,-1}}; 
    int n,m;
    char a[maxm][maxm];
    int vis[maxm][maxm];
    int sx,sy,ex,ey;
    struct node
    {
        int x,y,s;
    };
    bool check(int x,int y)
    {
        return x>=0 && y>=0 && x<n && y<m && a[x][y]!='*' && !vis[x][y];
    }
    
    void bfs(int sx,int sy)
    {
        queue<node> q;
        node tmp,nxt;
        tmp.x=sx, tmp.y=sy, tmp.s=0;
        vis[sx][sy]=1;
        q.push(tmp);
        while(!q.empty())
        {
            tmp = q.front();
            q.pop();
            if(a[tmp.x][tmp.y]=='T')
            {
                printf("%d
    ",tmp.s);
                return ;
            }
            for(int i=0;i<4;i++)//上/右/下/左
            {
                nxt.x = tmp.x + dx[i];
                nxt.y = tmp.y + dy[i];
                nxt.s = tmp.s + 1;
    //            printf("i=%d tmp.x=%d tmp.y=%d tmp.s=%d
    ",i,tmp.x,tmp.y,tmp.s);
    //
    //            printf("i=%d nxt.x=%d nxt.y=%d nxt.s=%d
    ",i,nxt.x,nxt.y,nxt.s);
    //            printf("-----------------------------------
    ");
                if(check(nxt.x,nxt.y))
                {
                    if(a[nxt.x][nxt.y]=='|')
                    {
                        nxt.x += dx[i];
                        nxt.y += dy[i];
    //                    printf("| i=%d tmp.x=%d tmp.y=%d tmp.s=%d
    ",i,tmp.x,tmp.y,tmp.s);
    //
    //                    printf("|> i=%d nxt.x=%d nxt.y=%d nxt.s=%d
    ",i,nxt.x,nxt.y,nxt.s);
    //                     printf("-----------------------------------
    ");
                        if(check(nxt.x,nxt.y))//判断到达楼梯时楼梯的方向和人前进的方向是否一致
                        {
                            //横-左右方向||竖-上下方向
                            //不顺路,原地不动,等待下次开门(如果楼梯正好反向了 时间需要加1)
                            if((tmp.s%2==0 && (i==1||i==3)) || (tmp.s%2==1 && (i==0||i==2)))
                                nxt.s+=1; //只需要判断当前的坐标与上一步坐标之间的关系,即可知道当前的方向与之前方向之间的关系即可
                        }
                        else continue;
                    }
                    else if(a[nxt.x][nxt.y]=='-')
                    {
                        nxt.x += dx[i];
                        nxt.y += dy[i];
    //                    printf("-  i=%d tmp.x=%d tmp.y=%d tmp.s=%d
    ",i,tmp.x,tmp.y,tmp.s);
    //
    //                    printf("-  i=%d nxt.x=%d nxt.y=%d nxt.s=%d
    ",i,nxt.x,nxt.y,nxt.s);
    //                     printf("-----------------------------------
    ");
                        if(check(nxt.x,nxt.y))//通过当前步数的奇偶性去判断当前楼梯的方向以及是否可以通行
                        {
                            if((tmp.s%2==0&&(i==0||i==2))||(tmp.s%2==1&&(i==1||i==3)))
                                nxt.s+=1;
                        }
                        else continue;
                    }
                    vis[nxt.x][nxt.y] = 1;
                    q.push(nxt);
                }
            }
        }
    }
    
    int main()
    {
    
        while(~scanf("%d%d",&n,&m))
        {
            memset(vis,0,sizeof(vis));
            getchar();
            for(int i=0;i<n;i++)
                scanf("%s",a[i]);
            for(int i=0;i<n;i++)
            {
                for(int j=0;j<m;j++)
                {
                    if(a[i][j]=='S')
                    {
                        sx=i;
                        sy=j;
                    }
                }
            }
    
            bfs(sx,sy);
        }
    
    }
    /*
    5 5
    **..T
    **.*.
    ..|..
    .*.*.
    S....
    */
    

    [优先队列]

    #include <iostream>
    #include <queue>
    #include <cstring>
    using namespace std;
    int n,m;
    const int maxn = 21;
    int stx,sty,gx,gy;
    char map[maxn][maxn];
    bool   vis[maxn][maxn];
    int statue[maxn][maxn];
    int dx[4]={0,0,1,-1};
    int dy[4]={-1,1,0,0};
    struct node{
    	int x,y,step;
    	/* friend bool operator <(node a,node b){
    		return a.step>b.step;
    	} */
    	bool operator <(const node &a)const{
    		return step>a.step;//步数小的先出队列
    	}
    }init;
    bool judge(node no){
    	//如果超出边界,或者该位置是墙,或者当前步数大于之前步数,返回false
    	if(no.x<0||no.x>=n||no.y<0||no.y>=m||map[no.x][no.y]=='*'||(statue[no.x][no.y]&&no.step>=statue[no.x][no.y]))
    		return false;
    	return true;
    }
    int bfs(){
    	init.x=stx;init.y=sty;init.step=0;
    	statue[init.x][init.y]=1;
    	priority_queue<node>pq;
    	while(!pq.empty()) 
    		pq.pop();
    	pq.push(init);
    	while(!pq.empty()){
    		node past=pq.top();
    		node now;
    		pq.pop();
    		for(int i=0;i<4;i++){
    			now.x=past.x+dx[i];
    			now.y=past.y+dy[i];
    			now.step=past.step+1;
    			if(!judge(now)) continue;
    			if(map[now.x][now.y]=='|'){
    				if(now.x==past.x&&(past.step & 1)==0) //当横着走,且 | 不变 
    					now.step++;
    				if(now.y==past.y&&(past.step & 1)==1)//当 竖着走 且 |变
    				{
    					now.step++;
    				}
    				now.x+=dx[i]; now.y+=dy[i];
    			}
    			else if(map[now.x][now.y]=='-'){
    				if(now.x==past.x&&(past.step & 1)==1) //当横着走,且 -变 
    					now.step++;
    				if(now.y==past.y&&(past.step & 1)==0)//当竖着走 且-不变
    					now.step++;
    				now.x+=dx[i]; now.y+=dy[i];
    			}
    			if(!judge(now)) continue;
    			if(map[now.x][now.y]=='T')
    				return now.step;
    			statue[now.x][now.y]=now.step;
    			pq.push(now);
    		}
    	}
    	return 0;
    }
    int main(){
    	while(cin>>n>>m){
    		for(int i=0;i<n;i++)
    			for(int j=0;j<m;j++){
    				cin>>map[i][j];
    				if(map[i][j]=='S')
    					stx=i,sty=j;
    				if(map[i][j]=='T')
    					gx=i,gy=j;
    			}
    			memset(statue,0,sizeof(statue));
    			int ans=bfs();
    			cout<<ans<<endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    在 Windows 上测试 Redis Cluster的集群填坑笔记
    vmware安装黑苹果教程
    微信支付v3发布到iis时的证书问题
    Linux下安装SQL Server 2016(连接篇SQL Server on linux)
    Linux下安装SQL Server 2016(连接篇SQL Server on linux)
    Linux下安装SQL Server 2016(安装篇SQL Server on linux)
    Linux下安装SQL Server 2016(准备篇SQL Server on linux)
    客服端与服务端APP支付宝支付接口联调的那些坑
    ASP.NET MVC]WebAPI应用支持HTTPS的经验总结
    .net平台下C#socket通信(中)
  • 原文地址:https://www.cnblogs.com/Roni-i/p/9201128.html
Copyright © 2011-2022 走看看