洛谷2243 电路维修 (双端队列维护最短路)

题目背景

Elf 是来自Gliese 星球的少女,由于偶然的原因漂流到了地球上。在她无依无靠的时候,善良的运输队员Mark 和James 收留了她。Elf 很感谢Mark和James,可是一直也没能给他们帮上什么忙。

题目描述

有一天 Mark 和James 的飞行车没有办法启动了,经过检查发现原来是电路板的故障。飞行车的电路板设计很奇葩,如下图所示:

这里写图片描述

输入输出格式

输入格式:

输入文件包含多组测试数据。第一行包含一个整数T 表示测试数据的数目。

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

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

对于40% 的数据,R,C≤5。

对于 100% 的数据,R,C≤500,T≤5。

输出格式:

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

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

输入输出样例

输入样例#1:

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

输出样例#1:

1

说明

样例的输入对应于题目描述中的情况。
这里写图片描述
只需要按照下面的方式旋转标准件,就可以使得电源和发动机之间连通。

题解

这道题网上的题解貌似不是很多,而且说法也不是很清楚

即使参考别人的代码自己也想了挺久的

这里把自己的想法写下来希望能对之后写这道题的同学有所帮助

首先我们需要理解题意,然后将它转化为我们所习惯的图,如下所示

对角线联通则边权为0,相反边权为1(需要花一费旋转)

不难发现变成了一道求最短路的图论题了(建图的时候记得多1行1列,但我没建

最后题目的答案,就是从(1,1)到(R,C)的最短路

但是别急,因为这道题把普通的SPFA卡掉了

所以这里我采用双端队列(deque)去维护

将能直达的(边权为0的)边加入队首,不能直达的(边权为1的)边加入队尾

这样的好处呢,就是每次都可以优先遍历边权为0的边,从而达到优化的效果

至于其他的操作呢,都是大同小异,直接上代码把

#include<deque>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
deque<pair<int,int> > dq;
pair<int,int> t;
int T,n,m,dis[505][505];
char a[505][505];
void work(int x,int y,int d,int bj)
{
    if(dis[x][y]>d+bj)
    {
        dis[x][y]=d+bj;
        if(bj) dq.push_back(pair<int,int>(x,y));
        else dq.push_front(pair<int,int>(x,y));
    }
}
void BFS()
{
    int x,y,now;
    dq.clear();
    dq.push_front(pair<int,int>(1,1));
    memset(dis,0x7f,sizeof dis);
    dis[1][1]=0;//多次数据记得初始化
    while(!dq.empty())
    {
        t=dq.front();
        dq.pop_front();
        x=t.first,y=t.second;
        now=dis[x][y];
        if(x>1&&y>1) work(x-1,y-1,now,a[x-1][y-1]!='\\');
        if(x>1&&y<=m) work(x-1,y+1,now,a[x-1][y]!='/'); 
        if(x<=n&&y>1) work(x+1,y-1,now,a[x][y-1]!='/'); 
        if(x<=n&&y<=m) work(x+1,y+1,now,a[x][y]!='\\');
    }
    printf("%d\n",dis[n+1][m+1]);
}
int main()
{
    scanf("%d",&T);
    for(int i=1;i<=T;++i)
    {
        scanf("%d%d",&n,&m);
        for(int j=1;j<=n;++j) scanf("%s",a[j]+1);
        if((n+m)%2) 
        {
            printf("NO SOLUTION\n");
            continue;
        }
        BFS();
    }
    return 0;
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值