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

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

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

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

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

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

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

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

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

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

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

输入格式

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

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

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

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

输出格式

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

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


emmmmm, 一道《算法进阶》上的题, 书中所给的方法是双端队列, 但身为蒟蒻的我怎么可能会,所以我想到了SPFA算法。

把每一个格点当做节点, 则共有(n + 1)* (m + 1)的节点, 在下图中, 就将1到4这条边的边权设为0, 而2到3这条边就为1,

通过这样的建图, 我们以1为起点, 跑一边最短路,输出终点的距离即可,注意的是, 当终点的距离为无限大时, 即到达不了终点, 输出NO SOLUTION;

比较坑的是, 这道题的数据竟然卡SPFA, 所以用Dijkstra就行了

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e6 + 100;
const int MAXM = 3e3 + 10; template < typename T > inline void read(T &x) {
x = 0; T ff = 1, ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') ff = -1;
ch = getchar();
}
while(isdigit(ch)) {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
x *= ff;
} template < typename T > inline void write(T x) {
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
} int T, n, m;
int vis[MAXN], dis[MAXN];
int lin[MAXN], tot = 0;
char ch;
struct edge {
int y, v, next;
}e[MAXN]; inline void add(int xx, int yy, int vv) {
e[++tot].y = yy;
e[tot].v = vv;
e[tot].next = lin[xx];
lin[xx] = tot;
} /*void SPFA() {
memset(dis, 0x3f, sizeof(dis));
memset(vis, false, sizeof(vis));
queue < int > q;
q.push(1);
dis[1] = 0;
while(!q.empty()) {
int x = q.front(); q.pop(); vis[x] = false;
for(int i = lin[x], y; i; i = e[i].next) {
if(dis[y = e[i].y] > dis[x] + e[i].v) {
dis[y] = dis[x] + e[i].v;
if(!vis[y]) {
vis[y] = true;
q.push(y);
}
} }
} }*/ void Dijkstra() {
memset(dis, 0x3f, sizeof(dis));
memset(vis, false, sizeof(vis));
priority_queue < pair < int, int > > q;
dis[1] = 0;
q.push(make_pair(0, 1));
while(!q.empty()) {
int x = q.top().second; q.pop();
if(vis[x]) continue;
vis[x] = true;
for(int i = lin[x], y; i; i = e[i].next) {
if(dis[y = e[i].y] > dis[x] + e[i].v) {
dis[y] = dis[x] + e[i].v;
if(!vis[y]) q.push(make_pair(-dis[y], y));
}
}
}
} int main() {
read(T);
while(T--) {
read(n); read(m);
memset(lin, 0, sizeof(lin));
memset(e, 0, sizeof(e));
tot = 0;
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= m; ++j) {
ch = getchar();
if(ch == '/') {
add(((i - 1) * (m + 1) + j), i * (m + 1) + j + 1, 1);
add(i * (m + 1) + j + 1, (i - 1) * (m + 1) + j, 1);
add(i * (m + 1) + j, (i - 1) * (m + 1) + j + 1, 0);
add((i - 1) * (m + 1) + j + 1, i * (m + 1) + j, 0);
}
else {
add(((i - 1) * (m + 1) + j), i * (m + 1) + j + 1, 0);
add(i * (m + 1) + j + 1, (i - 1) * (m + 1) + j, 0);
add(i * (m + 1) + j, (i - 1) * (m + 1) + j + 1, 1);
add((i - 1) * (m + 1) + j + 1, i * (m + 1) + j, 1);
}
}
ch = getchar();
}
// SPFA();
Dijkstra();
if(dis[(n + 1) * (m + 1)] == INF) puts("NO SOLUTION");
else write(dis[(n + 1) * (m + 1)]), puts("");
}
return 0;
}

今天, 某位机房大佬教了我双端队列, 思想大概和我上面的相同, 也是建一条0或1的边, 只是在搜索的过程中,将边权为0的加入队头, 1加入队尾, 这样每个节点可能多次入队, 但第一次弹出时就是最短距离

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 5e5 + 100;
const int MAXM = 3e3 + 10; template < typename T > inline void read(T &x) {
x = 0; T ff = 1, ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') ff = -1;
ch = getchar();
}
while(isdigit(ch)) {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
x *= ff;
} template < typename T > inline void write(T x) {
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
} int n, m, t;
int dis[MAXM][MAXM];
char ch[MAXM][MAXM]; int BFS() {
deque < pair < int, int > > q;
int dx[5] = {-1, -1, 1, 1}, dy[5] = {-1, 1, 1, -1};
int ix[5] = {-1, -1, 0, 0}, iy[5] = {-1, 0, 0, -1};
memset(dis, 0x3f, sizeof(dis));
q.push_back(make_pair(0, 0));
dis[0][0] = 0;
char s[6] = "\\/\\/";
while(!q.empty()) {
pair < int, int > c = q.front();
q.pop_front();
int x = c.first, y = c.second;
for(int i = 0; i < 4; ++i) {
int u = x + dx[i], v = y + dy[i];
int a = x + ix[i], b = y + iy[i];
if(u > n || u < 0 || v > m || v < 0) continue;
int w = 0;
if(ch[a][b] != s[i]) ++w;
if(dis[u][v] > dis[x][y] + w) {
dis[u][v] = dis[x][y] + w;
if(w) q.push_back(make_pair(u, v));
else q.push_front(make_pair(u, v));
}
}
}
return dis[n][m];
} int main() {
read(t);
while(t--) {
read(n); read(m);
for(int i = 0; i < n; ++i)
scanf("%s", &ch[i]);
int x = BFS();
if(x == INF) puts("NO SOLUTION");
else write(x), puts("");
}
return 0;
}

电路维修(双端队列 & 最短路)的更多相关文章

  1. CH 2601 - 电路维修 - [双端队列BFS]

    题目链接:传送门 描述 Ha'nyu是来自异世界的魔女,她在漫无目的地四处漂流的时候,遇到了善良的少女Rika,从而被收留在地球上.Rika的家里有一辆飞行车.有一天飞行车的电路板突然出现了故障,导致 ...

  2. Luogu P2243 电路维修 双端队列BFS

    当转移的代价是0和一个分明不同的权值时,可以用双端队列BFS去跑(你跑最短路也没问题..QWQ) 而对于这道题,边旋转代价是1,不旋转代价是0:可以直接建图最短路,也可以跑BFS 这个题建图很有意思: ...

  3. POJ3662 SPFA//二分 + 双端队列最短路

    https://cn.vjudge.net/problem/12427/origin 题意:求1到N第K + 1大条边权最小的路径 首先想到dp递推,dp[x][y]表示到x这个点经过y条免费边的最小 ...

  4. CH2601 电路维修(双端队列bfs)建图恶心

    CH2601 电路维修 双端队列bfs,其实就是因为只有0和1所以可以直接2维护队列单调性(和优先队列一个道理) 建图的过程需要仔细斟酌(想一想id为什么这么写) 还有,空间要开够(很玄学),我一开始 ...

  5. 2601 电路维修 (双端队列bfs\优先队列bfs(最短路))

    描述 Ha'nyu是来自异世界的魔女,她在漫无目的地四处漂流的时候,遇到了善良的少女Rika,从而被收留在地球上.Rika的家里有一辆飞行车.有一天飞行车的电路板突然出现了故障,导致无法启动. 电路板 ...

  6. 电路维修 (广搜变形-双端队列bfs)

    # 2632. 「BalticOI 2011 Day1」打开灯泡 Switch the Lamp On [题目描述] 有一种正方形的电路元件,在它的两组相对顶点中,有一组会用导线连接起来,另一组则不会 ...

  7. POJ 3662 Telephone Lines【二分答案+最短路】||【双端队列BFS】

    <题目链接> 题目大意: 在一个节点标号为1~n的无向图中,求出一条1~n的路径,使得路径上的第K+1条边的边权最小. 解题分析:直接考虑情况比较多,所以我们采用二分答案,先二分枚举第K+ ...

  8. P - The Shortest Path in Nya Graph-hdu4725(双端队列+拆点)

    题意:有N个点和N层..一层有X个点(0<=X<=N).两邻两层间有一条路花费C.还有M条小路在两个点之间.问从第一个点走到第N个点最短路是多少... 可以考虑在每一层增加一个点,这个点到 ...

  9. [lougu2243]双端队列搜索

    正统双端队列搜索 回顾:普通队列进行边权为定值的最短路 每次到达都是最优的(意味着不用取min) why? 因为所有状态按照 入队的先后顺序 具有 层次单调性,每次扩展,都往外走一步,满足从起始到该状 ...

随机推荐

  1. 九、Abp vNext 基础篇丨评论聚合功能

    介绍 评论本来是要放到标签里面去讲的,但是因为上一章东西有点多了,我就没放进去,这一章单独拿出来,内容不多大家自己写写就可以,也算是对前面讲解的一个小练习吧. 相关注释我也加在代码上面了,大家看看代码 ...

  2. vue-cli3 创建多页面应用项目

    1.创建vue项目 cmd命令执行  vue create ruc-continuing  创建vue项目,项目名称:ruc-continuing 选择一个 preset(预置项),或自定义: 选择自 ...

  3. 论文解读(SimCLR)《A Simple Framework for Contrastive Learning of Visual Representations》

    1 题目 <A Simple Framework for Contrastive Learning of Visual Representations> 作者: Ting Chen, Si ...

  4. 快乐中秋,SQL小白入门指南

    目录 创建表 最基本的创建 怎么查看一个已经建好的表的信息呢 修改字段 插入数据 修改和删除数据 修改 删除 第一个查询 条件语句 使用age的大小比较,查看大于16岁的学生: 使用多个条件并联,大于 ...

  5. springboot 配置 application.properties相关

    springboot 有读取外部配置文件的方法,如下优先级: 第一种是在jar包的同一目录下建一个config文件夹,然后把配置文件放到这个文件夹下.第二种是直接把配置文件放到jar包的同级目录.第三 ...

  6. 目标检测之pycocotools安装

    从清华镜像源下载https://pypi.tuna.tsinghua.edu.cn/simple/pycocotools-windows/ wheel型包,pycocotools_windows-2. ...

  7. git 切换分支

      # 查看git源 git  remote -v git remote set-url origin http://mingzhanghui@xx.xx.xx.xx:8090/r/ENSO/weba ...

  8. Java学习之随堂笔记系列——day03

    内容回顾:1.标识符和类型转换    1.1 标识符:给类.方法.变量取得名字就是标识符.        命名规则:            1.必须是字母.数字._.$组成            2. ...

  9. nginx 配置文件(支持thnkphp3.2~5)

    server { listen 8080 ; server_name localhost; set $root /var/www/myweb; #listen 443 ssl; #ssl_certif ...

  10. Radius协议-学习

    目录 RFC Radius 协议 Radius-学习 RADIUS协议的主要特征 客户端/服务器模式 安全的消息交互机制 良好的扩展性 AAA介绍 C/S结构 RADIUS在协议栈中的位置 RADIU ...