$Luogu$ $P2243$ 电路维修
背景
杜宇飞,石家庄二中【Nescafé 5】杯NOIP模拟赛, \(Luogu\) \(P2243/CH2601\)
题意
对于 \(T\) 组数据,每次给定一个 \(r \times c\) 的网格,分别为字符左右斜杠表示电路的方向。电流可以经过电路和格点流动。每个格子可以自由旋转任意次,每次只能旋转 \(90^\circ\) 。求从左上角的格点到右下角的格点有电流经过的最小旋转次数。若电流不能到达输出 \(\textrm{NO SOLUTION}\) 。
解法
显然每个格子只可能是不动或者旋转一次的,否则必然不优。
考虑怎么建图。不妨考虑把所有的格点形成一个 \((r+1) \times (c+1)\) 的点阵,分别从 \(1\) 到 \((r+1) \times (c+1)\) 编号。这样就可以考虑对每个网格的对角线连边了。由于本身就存在电路的对角线不需要移动,所以建 \(0\) 边;若所在网格的电路与当前的对角线垂直,则沿着任意方向旋转一次就可以有电流流经,于是建 \(1\) 边。
然后就是跑最短路了。
堆优化 \(dijkstra\) 当然是可以过的,但是不够快。可以考虑线段树优化。这里不多讲了。
如果你要用那个死了的算法的话,显然网格图能把你卡飞。
由于边权只有 \(1\) 和 \(0\) 两种,考虑 \(0-1\) \(bfs\) (双端队列 \(bfs\) )。做法是 \(0\) 边放进队首, \(1\) 边放进队尾。其他的细节和那个死了的算法没有啥区别。唯一的区别是不用判断能不能松弛,大力取 \(min\) 就是了。
细节
\(1.\) 请务必务必务必建无向边!!!
\(2.\) 有字符串读入建议用 \(cin\) 。读进来立马建好边,注意从 \(0\) 开始标号。
\(3.\) 记得初始化 \(dis\) 为\(inf\) ,后面还要判无解。
\(4.\) 多组数据,该清空的都要清空。
代码
\(View\) \(Code\)
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int ret=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
ret=(ret<<1)+(ret<<3)+ch-'0';
ch=getchar();
}
return ret*f;
}
const int inf=0x3f3f3f3f;
int T,r,c,dis[300005];
int num,head[300005];
char s[505];
bool vis[300005];
deque<int> q;
struct edge
{
int ver,nxt,w;
}e[2000005];
inline void adde(int u,int v,int w)
{
e[++num].ver=v;
e[num].nxt=head[u];
e[num].w=w;
head[u]=num;
}
inline void bfs(int s)
{
q.clear();
dis[s]=0;
q.push_front(s);
while(!q.empty())
{
int x=q.front();
q.pop_front();
if(vis[x])
continue;
vis[x]=1;
for(register int i=head[x];i;i=e[i].nxt)
{
int y=e[i].ver;
if(e[i].w)
{
dis[y]=min(dis[y],dis[x]+1);
q.push_back(y);
}
else
{
dis[y]=min(dis[y],dis[x]);
q.push_front(y);
}
}
}
}
int main()
{
T=read();
while(T--)
{
r=read();
c=read();
num=0;
memset(head,0,sizeof(head));
for(register int i=1;i<=r;i++)
{
scanf("%s",s);
for(register int j=1;j<=c;j++)
{
int leftup=(i-1)*(c+1)+j,leftdown=i*(c+1)+j,rightup=(i-1)*(c+1)+j+1,rightdown=i*(c+1)+j+1;
if(s[j-1]=='\\')
{
adde(leftup,rightdown,0);
adde(rightdown,leftup,0);
adde(leftdown,rightup,1);
adde(rightup,leftdown,1);
}
else
{
adde(leftup,rightdown,1);
adde(rightdown,leftup,1);
adde(leftdown,rightup,0);
adde(rightup,leftdown,0);
}
}
}
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
bfs(1);
if(dis[(r+1)*(c+1)]<inf)
printf("%d\n",dis[(r+1)*(c+1)]);
else
printf("NO SOLUTION\n");
}
return 0;
}
原文地址:https://www.cnblogs.com/Peter0701/p/11847216.html
- 2018年,让你的数据库变更快的十个建议
- Hadoop如何使用Zookeeper来保障高可用?
- HTTP 压力测试工具 wrk
- 理解 Linux shell 中的一个方言:2>&1
- 大家知道什么是git中的 .gitignore吗?
- MySQL 8.0 新特性 :隐藏索引 Invisible Indexes
- 如何监控MySQL的复制延迟?
- Uber 的 Docker Mysql 应用
- Dubbo源码-从HelloWorld开始
- 【深度学习】用PaddlePaddle进行车牌识别(二)
- JavaScript 10分钟入门
- 外键约束
- OpenCV3.x中UMat介绍与使用
- OpenCV中KMeans算法介绍与应用
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- R语言基于Reactome数据库的富集分析
- WiredTiger存储引擎之五:与事务相关的数据结构以及并发控制机制
- Tomcat NIO(8)-Poller线程的阻塞与唤醒
- 你的第一个React App (一 ) - 项目初始化
- 被JDK坑的没商量?来试试这些方法吧
- k8s 代码走读---client-go 编程交互测试代码
- C#网络类智能开关控制板实例
- Flume拦截器实现按照事件时间接入HDFS
- Day4.Linux用户权限
- 如何使用Canal同步MySQL的Binlog到Kafka
- Go 每日一库之 gabs
- 如何将Flink应用的日志发送到kafka
- 锦囊篇|Java中的SPI机制
- webpack实战——生产环境配置【上】
- 深度阅读之《Concurrency in Go》