Acwing 175电路维修

题意:

本题问我们就是从电源处到达终点,我们需要转动每个格子中线路最少次数,如果不管怎么转动都到达不了就输出 "NO SOLUTION"。

首先这个题要区分普通的bfs

首先本题跑的不是格子,是节点,要从最左上节点跑到最右下节点

还要根据每个格子的图形形状判断走的步数:

        如果当前节点可以直接划到下一节点就可以我们认为步长为0它压入队头(电流可以直接流入);

        如果需要旋转才能到达下一节点(接通电路),那么该步长为1,压入队尾。

因为每个格子的图形是  "/,\";所以每个节点不能到达该节点的上下左右的临节点,而是斜方向

比如目前我们在0号点这个位置,那我们到三号点所需要的步长是0,到2号点的步长是1,我们需要将这个电线顺时针转动90°,注意我们这儿说的步长是需不需要转动最短路不需要转动步长为0,需要则为1。

首先先考虑不可能的情况,因为我们只能沿着斜线走,只有两种方式"/  \", 所以我们永远到达不了横纵坐标之和为奇数的点,所以只要我们终点的横纵坐标之和为奇数就是

不可能的

 

因为蓝色线使我们的起点不能移动我们这样才能和电源连接,然后圈出的点,不管你怎么旋转红色的线,前提是你要连通电源这根线,那么一定到达不了这些点

 而后因为我们实现的是最小次数,这些步长为0的点应该放在队头,让我们优先来判断,其次再判断步长为一的点

 

#include <bits/stdc++.h>

#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;
typedef long long ll;

const int N = 1e3 + 10;
const int dx[] = {0, -1, 0, 1}, dy[] = {-1, 0, 1, 0};//遍历当前节点能到达的哪些节点的
const int ix[] = {-1, -1, 0, 0}, iy[] = {-1, 0, 0, -1};//当前节点四周格子内的图形是什么


int n, m, t;
int g[N][N];//存图
int dist[N][N];
bool st[N][N];//判重,你如果确定了这个线的放置,就不再去旋转改变它的走向

int bfs()
{
     deque<PII> q;
     memset(dist, 0x3f, sizeof dist);
     memset(st, 0, sizeof st);
     
     char cs[] = "\\/\\/";//四种图形
     
     q.push_back({0,0});

     while(!q.empty())
     {
          auto t = q.front();
          q.pop_front();

          if(st[t.x][t.y]) continue;
          st[t.x][t.y] = true;

          for(int i = 0; i < 4; i ++)
          {
               int ss = t.x + dx[i];
               int dd = t.y + dy[i];

               if(ss < 0 || ss > n || dd < 0 || dd > m) continue;//越界

               int ga = t.x + ix[i], gb = t.y + iy[i];//该节点四周图形的坐标
               int d = dist[t.x][t.y] + (g[ga][gb] != cs[i]);//当前遍历到的节点如果与上一节点不同那么距离加1

               if(d < dist[ss][dd])
               {
                    dist[ss][dd] = d;

                    if(g[ga][gb] != cs[i]) q.push_back({ss, dd});//如果图案不同,步长为1压入队尾
                    else q.push_front({ss, dd});//图案相同,步长为0压入队首
               }
          }
     }
     return dist[n][m];
}

void solve()
{
     cin >> n >> m;
     for(int i = 0; i < n; i ++)
          for(int j = 0; j < m; j ++)
               cin >> g[i][j];

     if(n*m & 1) puts("NO SOLUTION");
     else cout << bfs() << endl;
}

signed main()
{
     IOS;
     cin >> t;
     while(t--)
          solve();
     return 0;
}

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值