uva 705 Slash Maze(斜线迷宫) —— DFS

本文全部摘抄自下述网站,只添加本人的一点理解

参考网站:网易博客

/**
序号:num_5
作者:MrZhang
日期:2016-5-24


题目名称: Slash Maze(斜线迷宫)
题目来源:
uva —— 705 —— Slash Maze
网址:
英文题目:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19488
--------------------------------------
数据样例:
input:

6 4
\//\\/
\///\/
//\\/\
\/\///
3 3
///
\//
\\\
0 0

output

Maze #1:
2 Cycles; the longest has length 16.
Maze #2:
There are no cycles.
*/

#include <iostream>
#include <cstring>
#define MAXN 160
using namespace std;

int G[MAXN][MAXN],n,m,sum,maxlen;//!sum :当前环的长度 maxlen:最长环的长度

//!                      0      1     2     3      4      5     6      7
//!                     上     下    左    右    左上   右下  左下   右上
const int _move[8][2]={{-1,0},{1,0},{0,-1},{0,1},{-1,-1},{1,1},{1,-1},{-1,1}};
bool vis[MAXN][MAXN],flag;

void dfs(int x,int y)
{
    vis[x][y]=true;
    int px,py;
    sum++;

    if(x==0 || y==0 || x==2*n-1 || y==2*m-1) {
          flag=true;
    }

    for(int i=0;i<8;++i)
    {
        px=x+_move[i][0];
        py=y+_move[i][1];
        if(px>=0 && px<2*n && py>=0 && py<2*m && G[px][py]!=1 && !vis[px][py])
        {
            if(i<4) dfs(px,py);
            else
            {
                if(i==4 && G[x-1][y]==1 && G[x][y-1]==1)//左上
                {
                    if((G[x-1][y-2]==1 && G[x][y+1]==1 && (x&1) && !(y&1)) ||
                       (G[x-2][y-1]==1 && G[x+1][y]==1 && !(x&1) && (y&1)))
                    {
                        dfs(px,py);
                    }
                }
                if(i==5 && G[x][y+1]==1 && G[x+1][y]==1)//右下
                {
                    if((G[x+1][y+2]==1 && G[x][y-1]==1 && !(x&1) && (y&1)) ||
                       (G[x-1][y]==1 && G[x+2][y+1]==1 && (x&1) && !(y&1)))
                    {
                        dfs(px,py);
                    }
                }
                if(i==6 && G[x][y-1]==1 && G[x+1][y]==1)//左下
                {
                    if((G[x-1][y]==1 && G[x+2][y-1]==1 && (x&1) && (y&1)) ||
                       (G[x][y+1]==1 && G[x+1][y-2]==1 && !(x&1) && !(y&1)))
                    {
                        dfs(px,py);
                    }
                }
                if(i==7 && G[x-1][y]==1 && G[x][y+1]==1)//右上
                {
                    if((G[x][y-1]==1 && G[x-1][y+2]==1 && (x&1) && (y&1)) ||
                       (G[x+1][y]==1 && G[x-2][y+1]==1 && !(x&1) && !(y&1)))
                    {
                        dfs(px,py);
                    }
                }
            }
        }
    }
}

void solve()
{
    sum=0; maxlen=0;
    int cnt=0;
    for(int i=0;i<2*n;++i)
    {
        for(int j=0;j<2*m;++j)
        {
            if(G[i][j]==0 && !vis[i][j])
            {
                sum=0;
                flag=false;//!进入图开始遍历,怎样才算是一个环呢?只要在遍历的过程中没有
                dfs(i,j);
                if(!flag)
                {
                    if(maxlen<sum) maxlen=sum;
                    sum=0;
                    cnt++;
                }
            }
        }
    }

    if(cnt) cout<<cnt<<" Cycles; the longest has length "<<maxlen<<"."<<endl;
    else cout<<"There are no cycles."<<endl;
}
void read_input()
{
    char s[80];
    memset(G,0,sizeof(G));
    memset(vis,false,sizeof(vis));
    for(int i=0;i<2*n;i+=2)
    {
        cin>>s;
        for(int j=0;j<m;j++)
        {
            if(s[j]=='\\') G[i][j*2]=G[i+1][2*j+1]=1;
            else G[i][2*j+1]=G[i+1][2*j]=1;
        }
    }
}
//void out_put()
//{
//    for(int i=0;i<2*n;++i)
//    {
//        for(int j=0;j<2*m;++j)
//        {
//            if(G[i][j]) cout<<"1";
//            else cout<<"0";
//        }
//        cout<<endl;
//    }
//    cout<<endl;
//}
int main()
{
    int T=1;
    while(cin>>m>>n)
    {
        if(m+n==0) break;
        cout<<"Maze #"<<T++<<":"<<endl;
        read_input();
        solve();
        cout<<endl;
        //out_put();
    }
    return 0;
}

/**

总结:

题型:图的遍历

原理:DFS

技巧:使用四个二进制数表示一个斜线

针对此题目的理解:

1.首先是环的概念,怎样才算是一个环呢?
见英文,注意两句:
(1)paths in the maze cannot branch.
(2)the whole maze only contains cyclic paths and paths entering somewhere and leaving somewhere else

解释:
由上可知:
在此迷宫中不存在分支,即'Y'型的路。
所以 只存在两种路:a.单方向的环 b.路的两端均在迷宫的边上(注意到了边就不可能再回来了)

*/


2. flag标志的作用

如下图:黄色代表边界,灰色代表路径,红点代表开始遍历的点。

所以,下面的路即上面的'b'型路径。

序号(1)(2)代表遍历的顺序。


过程分析:

首先从红点沿着(1)方向遍历,在遍历过程中不断将visited设置为1。到达迷宫边界后将flag设置为true,因为不能再走了,所以不断回溯至红色原点处。

然后朝其他可走的方向遍历(此处即(2)方向了),同样设置visited,

想想沿着方向2会发生什么情况?成环了!!!可这种环是无效的。

但仍然会正常的遍历完,目的是将这条假环的visited全设置成1,以免以后再遍历。


遍历完后,这次dfs全部结束,那么问题来了,程序会将这个环计算在内吗?(即cnt 会 ++吗?)

不会,因为在这次遍历中,上面的(1)已经导致了flag设置为true,而

 if(!flag)
{
       if(maxlen<sum) maxlen=sum;
       sum=0;
       cnt++;
}
所以,该次遍历不会计数在内。

故而,真是由于flag的存在才避免了这种假环的计数。


                                  图1


3.sum,为什么在某部分方向的遍历失败后,回溯到原点后没有将sum恢复原值?

请看上面的a.b.c三种路,因为只有bc型路都到过边界,所以其flag都设置为true了,这些错误的路的sum不会被采纳。

只有a型路,这种正确的单方向的路的sum才会被采纳,所以不用担心sum失误。


其实,即使恢复sum 也是可以的。只有稍有点麻烦罢了。 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张之海

若有帮助,客官打赏一分吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值