电路维修——解题报告

题目链接:http://172.18.70.217/problem/19
题目大意:通过改变格子中正反斜杠方向找到一条从起点到终点的路径,并使改变斜杠方向的次数最少。
通过分析我们很容易发现,我们可以将格子的四个角当成4个点,而斜杠本身当成一条边。那么对于一个点来说,与之相邻的点就有两种:
第一种:能够不改变斜杠方向就能到达的点。
第二种:通过改变斜杠方向后就能到达的点。
那么我们可以通过求出从起点到(x,y)这个点需要改变斜杠方向的次数,从而逐步求出其周围点的情况,最后求出到(R+1,C+1)这个点需要改变的最小次数(因为是以顶点作为新的点,所以长和宽都变大了)。那么我们很容易就可以想到通过BFS得到答案。但是一些需要注意的地方:
1.开两个队列,一个是正常的遍历队列s,另一个是将之前遍历过的点存储下来进行其它的遍历New
2.先将从队列s的队首元素出发,不需要改变斜杠的方向就可到达的点,然后将这所有遍历过的点都压入另一个队列中。
3.当队列s为空时,开始遍历队列New中的点,获得从这一些点出发只需改变一次斜杠就能到达的点,直到队列New为空为止。
达成以上三点就可以避免出现,本来可以以更少的次数得到的答案,在更大次数背景下先被访问的问题。
下面附上AC代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <queue>

using namespace std;
typedef int ll;
char mp[1010][1010];
bool vis[1010][1010];
ll R,C,flag=0;
ll cx[4]={-1,-1,1,1};
ll cy[4]={-1,1,-1,1};
struct node
{
    ll x;
    ll y;
    ll times;
};
void bfs()
{
    memset(vis,false,sizeof(vis));
    queue<node> s;
    queue<node> New;
    node fir;
    fir.x=1;fir.y=1;fir.times=0;
    s.push(fir);
    vis[1][1]=true;
    ll ans=0;
    while(!s.empty())
    {
        node u=s.front();
        s.pop();
        if(u.x==R+1 && u.y==C+1)
        {
            printf("%d\n",u.times);
            flag=1;
            return;
        }
        for(ll i=0;i<4;i++)
        {
            node v=u;
            v.x=u.x+cx[i];
            v.y=u.y+cy[i];
            if(!vis[v.x][v.y] && v.x>=1 && v.x<=R+1 && v.y>=1 && v.y<=C+1)
            {
                if(i==0 && mp[u.x-1][u.y-1]=='\\')
                {
                    vis[v.x][v.y]=true;
                    s.push(v);
                }
                if(i==1 && mp[u.x-1][u.y]=='/')
                {
                    vis[v.x][v.y]=true;
                    s.push(v);
                }
                if(i==2 && mp[u.x][u.y-1]=='/')
                {
                    vis[v.x][v.y]=true;
                    s.push(v);
                }
                if(i==3 && mp[u.x][u.y]=='\\')
                {
                    vis[v.x][v.y]=true;
                    s.push(v);
                }
            }
        }
        New.push(u);
        if(!s.empty())
            continue;
        while(!New.empty())
        {
            u=New.front();
            New.pop();
            for(ll i=0;i<4;i++)
            {
                node v=u;
                v.x=u.x+cx[i];
                v.y=u.y+cy[i];
                v.times++;
                if(!vis[v.x][v.y] && v.x>=1 && v.x<=R+1 && v.y>=1 && v.y<=C+1)
                {
                    if(i==0 && mp[u.x-1][u.y-1]=='/')
                    {
                        vis[v.x][v.y]=true;
                        s.push(v);
                    }
                    if(i==1 && mp[u.x-1][u.y]=='\\')
                    {
                        vis[v.x][v.y]=true;
                        s.push(v);
                    }
                    if(i==2 && mp[u.x][u.y-1]=='\\')
                    {
                        vis[v.x][v.y]=true;
                        s.push(v);
                    }
                    if(i==3 && mp[u.x][u.y]=='/')
                    {
                        vis[v.x][v.y]=true;
                        s.push(v);
                    }
                }
            }
        }
    }
}
int main()
{
    ll T;
    cin>>T;
    while(T--)
    {
        cin>>R>>C;
        for(ll i=1;i<=R;i++)
            for(ll j=1;j<=C;j++)
                cin>>mp[i][j];
        flag=0;
        bfs();
        if(flag==0)
            printf("NO SOLUTION\n");
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值