AcWing 175. 电路维修

AcWing 175. 电路维修

题目链接

175. 电路维修

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

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

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

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

image

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

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

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

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

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

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

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

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

输入格式

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

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

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

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

输出格式

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

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

数据范围

1R,C500,
1T5

输入样例:

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

输出样例:

1

样例解释

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

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

image

解题思路

01bfs

把每一个横竖交点作为结点,当对角线与电缆重合时,权值为 0,否则为 1(即旋转电缆),转化为从左上角到右小角的最小权值,可利用双端队列的bfs,权值为 0 则进队首,否则进队尾,即每次优先扩展权值小的,遍历到终点时可保证最短。另外,需要注意如何用一个值表示一个坐标保证值不重复

  • 时间复杂度:O(T×R×C)

代码

#include<bits/stdc++.h> using namespace std; const int N=300000; int t,n,m,d[N]; char g[505][505]; vector<pair<int,int>> adj[N]; bool vis[N]; void bfs() { memset(d,0x3f,sizeof d); memset(vis,0,sizeof vis); deque<int> q; q.push_back(0); d[0]=0; while(q.size()) { int x=q.front(); q.pop_front(); if(x==n*(m+1)+m)break; if(vis[x])continue; vis[x]=true; for(auto [y,w]:adj[x]) { if(d[y]>d[x]+w) { d[y]=d[x]+w; if(w)q.push_back(y); else q.push_front(y); } } } } int main() { for(scanf("%d",&t);t;t--) { scanf("%d%d",&n,&m); for(int i=0;i<n;i++) scanf("%s",g[i]); for(int i=0;i<N;i++)adj[i].clear(); //对角线 for(int i=0;i<n;i++) for(int j=0;j<m;j++) adj[i*(m+1)+j].emplace_back((i+1)*(m+1)+j+1,g[i][j]!='\\'),adj[(i+1)*(m+1)+j+1].emplace_back(i*(m+1)+j,g[i][j]!='\\'); //反对角线 for(int i=0;i<n;i++) for(int j=1;j<=m;j++) adj[i*(m+1)+j].emplace_back((i+1)*(m+1)+j-1,g[i][j-1]!='/'),adj[(i+1)*(m+1)+j-1].emplace_back(i*(m+1)+j,g[i][j-1]!='/'); if((n+m)&1)puts("NO SOLUTION"); else { bfs(); printf("%d\n",d[n*(m+1)+m]); } } return 0; }

2019. 拖拉机

题目链接

AcWing 2019. 拖拉机

干了一整天的活,农夫约翰完全忘记了他把拖拉机落在田地中央了。

他的奶牛非常调皮,决定对约翰来场恶作剧。

她们在田地的不同地方放了 N 捆干草,这样一来,约翰想要开走拖拉机就必须先移除一些干草捆。

拖拉机的位置以及 N 捆干草的位置都是二维平面上的整数坐标点。

拖拉机的初始位置上没有干草捆。

当约翰驾驶拖拉机时,他只能沿平行于坐标轴的方向(北,南,东和西)移动拖拉机,并且拖拉机必须每次移动整数距离。

例如,驾驶拖拉机先向北移动 2 单位长度,然后向东移动 3 单位长度。

拖拉机无法移动到干草捆占据的位置。

请帮助约翰确定他需要移除的干草捆的最小数量,以便他能够将拖拉机开到二维平面的原点。

输入格式

第一行包含三个整数:N 以及拖拉机的初始位置 (x,y)

接下来 N 行,每行包含一个干草捆的位置坐标 (x,y)

输出格式

输出约翰需要移除的干草捆的最小数量。

数据范围

1N50000,
1x,y1000

输入样例:

7 6 3 6 2 5 2 4 3 2 1 7 3 5 4 6 4

输出样例:

1

解题思路

01bfs

这里不是边权而是点权,同样可以按照01bfs处理,从起点开始bfs,如果遇到干草捆,则点权为 1,否则为 0,即转换为从起点到终点的最短路,注意这里可以到达边界后再从边界到达终点,所以实际边界要扩展一个长度

  • 时间复杂度:O(4×10002)

代码

#include<bits/stdc++.h> using namespace std; const int N=1005; int d[N][N],sx,sy,dx[4]={-1,0,1,0},dy[4]={0,1,0,-1}; bool v[N][N],st[N][N]; void bfs() { memset(d,0x3f,sizeof d); memset(v,0,sizeof v); d[sx][sy]=0; deque<pair<int,int>> q; q.push_front({sx,sy}); while(q.size()) { auto [x,y]=q.front(); q.pop_front(); if(x==1&&y==1)break; if(v[x][y])continue; v[x][y]=true; for(int i=0;i<4;i++) { int nx=x+dx[i],ny=y+dy[i]; if(nx<0||nx>1001||ny<0||ny>1001)continue; if(d[nx][ny]>d[x][y]+st[nx][ny]) { d[nx][ny]=d[x][y]+st[nx][ny]; if(st[nx][ny]) q.push_back({nx,ny}); else q.push_front({nx,ny}); } } } } int main() { int x,y,n; scanf("%d%d%d",&n,&sx,&sy); while(n--) { scanf("%d%d",&x,&y); st[x][y]=true; } bfs(); printf("%d",d[1][1]); return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/15834929.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(57)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示