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