AcWing 175. 电路维修


AcWing 175. 电路维修

题目链接

175. 电路维修

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

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

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

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

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

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

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

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

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

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

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

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

输入格式

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

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

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

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

输出格式

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

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

数据范围

\(1≤R,C≤500\),
\(1≤T≤5\)

输入样例:

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

输出样例:

1

样例解释

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

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

解题思路

01bfs

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

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

代码

#include
using namespace std;
const int N=300000;
int t,n,m,d[N];
char g[505][505];
vector> adj[N];
bool vis[N];
void bfs()
{
    memset(d,0x3f,sizeof d);
    memset(vis,0,sizeof vis);
    deque 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

2019. 拖拉机

题目链接

AcWing 2019. 拖拉机

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

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

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

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

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

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

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

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

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

输入格式

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

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

输出格式

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

数据范围

\(1≤N≤50000\),
\(1≤x,y≤1000\)

输入样例:

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\times 1000^2)\)

代码

#include
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> 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;
}