电路维修(双端队列广搜)

达达是来自异世界的魔女,她在漫无目的地四处漂流的时候,遇到了善良的少女翰翰,从而被收留在地球上。

翰翰的家里有一辆飞行车。

有一天飞行车的电路板突然出现了故障,导致无法启动。

电路板的整体结构是一个 R 行 C 列的网格(R,C≤500),如下图所示。

电路.png

每个格点都是电线的接点,每个格子都包含一个电子元件。

电子元件的主要部分是一个可旋转的、连接一条对角线上的两个接点的短电缆。

在旋转之后,它就可以连接另一条对角线的两个接点。

电路板左上角的接点接入直流电源,右下角的接点接入飞行车的发动装置。

达达发现因为某些元件的方向不小心发生了改变,电路板可能处于断路的状态。

她准备通过计算,旋转最少数量的元件,使电源与发动装置通过若干条短缆相连。

不过,电路的规模实在是太大了,达达并不擅长编程,希望你能够帮她解决这个问题。

注意:只能走斜向的线段,水平和竖直线段不能走。

输入格式:

输入文件包含多组测试数据。

第一行包含一个整数 T,表示测试数据的数目。

对于每组测试数据,第一行包含正整数 R和 C,表示电路板的行数和列数。

之后 R行,每行 C 个字符,字符是"/""\"中的一个,表示标准件的方向。

输出格式:

对于每组测试数据,在单独的一行输出一个正整数,表示所需的最小旋转次数。

如果无论怎样都不能使得电源和发动机之间连通,输出 NO SOLUTION

数据范围:

1≤R,C≤500,
1≤T≤5

输入样例:

1
3 5
\\/\\
\\///
/\\\\

输出样例: 

1

样例解释: 

样例的输入对应于题目描述中的情况。

只需要按照下面的方式旋转标准件,就可以使得电源和发动机之间连通。

电路2.png

关于ixiy和dxdy——格点偏移和坐标点偏移 

寻找最短路是从一条斜线的源点出发,一条斜线会有两个坐标点,一个坐标点有四个偏移方向

例如从坐标点(1,1)可以到到(0,2),(0,0),(2,0),(2,2),那么便可以很容易地写出坐标点的方向数组了,同时我们需要考虑坐标点在偏移的时候其跨越的格子中的斜线是否能连通,所以我们需要数组string cs来存储坐标点四个方向的路线形状,例如int dian_ne[4][2]={{-1,-1},{-1,1},{1,-1},{1,1}};那么对应的cs="\\//\\"(注意‘\\'为转义字符,左上 \ ,右上 / ,左下 / ,右下 \  ),格点坐标是坐标点所跨越的格子的位置,那么格点的方向数组也要与坐标点的方向数组对应,int ge_ne[4][2]={{-1,-1},{-1,0},{0,-1},{0,0}};

然后我们需要判断格点位置的斜线是否与cs对应的斜线是否相同,若不同则说明需要旋转才能连通,此时“边权”为1,如果连通则“边权为0。

根据Dijkstra算法的思想求最短步数,应将每次步数少的优先出队,本题也借用此思想来做,若边权为1,则放入双端队列的队尾,否则放入队头。

(注意:cs 、ge_ne,dian_ne三者必须按照统一的方向构造)

代码: 

 

#include<iostream>
#include<deque>
#include<cstring>
#include<algorithm>
using namespace std;
typedef pair<int,int> PII;
const int N=505;
int gne[4][2]={{-1,-1},{-1,0},{0,-1},{0,0}};
int dne[4][2]={{-1,-1},{-1,1},{1,-1},{1,1}};
char a[N][N];
int dist[N][N];
int h,l;
bool st[N][N];
void bfs()
{
    memset(st,false,sizeof st);
    deque<PII> q;
    q.push_front({0,0});
    memset(dist,0x3f,sizeof dist);
    dist[0][0]=0;
    string cs="\\//\\";
    while(q.size())
    {
        auto it=q.front();q.pop_front();
        int x=it.first,y=it.second;
        if(x==h&&y==l)
        {
            cout<<dist[x][y];
            return ;
        }
        if(st[x][y]) continue;
        st[x][y]=true;
        for(int i=0;i<=3;i++)
        {
            int tx=x+dne[i][0],ty=y+dne[i][1];
            if(tx>=0&&tx<=h&&ty>=0&&ty<=l)
            {
                int ga=x+gne[i][0],gb=y+gne[i][1];
                int w=a[ga][gb]==cs[i]?0:1;
                if(dist[tx][ty]>dist[x][y]+w)
                {
                    dist[tx][ty]=dist[x][y]+w;
                    if(w) q.push_back({tx,ty});
                    else q.push_front({tx,ty});
                }
            }
        }
    }
    cout<<"NO SOLUTION";
    return ;
}
int main()
{
    int t;cin>>t;
    while(t--)
    {
        cin>>h>>l;
        memset(a,'\0',sizeof a);
        for(int i=0;i<h;i++)
        for(int j=0;j<l;j++)
        cin>>a[i][j];
        bfs();
        puts("");
    }
}
  • 26
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

SuperRandi

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值