手机的诱惑--dfs+矩阵奇偶性剪枝

手机的诱惑

题目大意:

给你一个N*M(1<N,M<7)的字符矩阵,其中包含字符含义:

‘X’:不能进入的墙
‘S’:起点
‘D’:门
‘.’:可以行走的地方

问:若每个点只能走一次,每次只能走上下左右4个方向,从起点到门的是否存在长度恰好为T(0<T<50)的路径?

用例输入 

4 4 5
S.X.
..X.
..XD
....
3 4 5
S.X.
..X.
...D
0 0 0

用例输出 

NO
YES

思路

bfs不太适合:bfs会先考虑周围的点,逐步进行“扩散”搜索,不能直接“绕远路”,求恰好长度为T的路径可能会“绕远路”,不能穷举所有情况。故采用dfs。

奇偶性剪枝:直接写dfs还是会TLE(原来没想到这玩意儿,尝试剪枝了无数次,同时TLE了无数次,我服了),所以要用到一个很重要的奇偶性剪枝。

考虑两个点:p1:(x1,y1),p2:(x2,y2),则从p1到p2的路径长度的奇偶性与两坐标的奇偶性有关,若(x1+y1)%2==(x2+y2)%2,则p1到p2无论怎么走,路径长度都是偶数,反之都是奇数。

举个例子,拿最简单的相邻的两个点来说,路径长度为1,无论怎么走,路径长度都是奇数,因为他们各自的横纵坐标之和的奇偶性不一样。

代码

#include<bits/stdc++.h>
using namespace std;
int n,m,t;
char mp[10][10];
bool st[10][10];
int ans;
int sta_x,sta_y;
int ed_x,ed_y;
int dfs(int d,int x,int y)
{
    if(d==t)return mp[x][y]=='D'?1:0;
    if(mp[x][y]=='D')
    {
        return d==t?1:0;
    }
    if(((x+y)%2+(ed_x+ed_y)%2)%2!=abs(d-t)%2)//矩阵奇偶性优化
    {
        return 0;
    }
    
    int dx[4]={0,0,1,-1};
    int dy[4]={1,-1,0,0};
    int res=0;
    for(int i=0;i<4;i++)
    {
        int xx=x+dx[i];
        int yy=y+dy[i];
        if(xx>=0&&yy>=0&&xx<n&&yy<m&&mp[xx][yy]!='X'&&!st[xx][yy])
        {
            st[xx][yy]=1;
            if(dfs(d+1,xx,yy))return 1;
            st[xx][yy]=0;
        }
    }
    return 0;
    
}
void solve()
{
    ans=0;
    memset(st,0,sizeof st);
    for(int i=0;i<n;i++)
        cin>>mp[i];
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(mp[i][j]=='S')
                sta_x=i,sta_y=j;
            if(mp[i][j]=='D')
                ed_x=i,ed_y=j;
        }
    }
    st[sta_x][sta_y]=1;
    ans=dfs(0,sta_x,sta_y);
    if(ans)
        cout<<"YES"<<endl;
    else cout<<"NO"<<endl;
}
int main()
{
    while(cin>>n>>m>>t,n,m,t)
        solve();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值