信奥一本通 1394:连接格点(grid)

这篇博客介绍了如何应用Kruskal算法解决一个二维点阵的连通性问题。给定一个MM行NN列的点阵,已知某些点之间存在连线,目标是最小化额外连线的成本以确保所有点全部连通。通过遍历纵向和横向的连线,按照单位成本进行连接,并使用并查集维护连通性。示例中展示了对于一个2x2的点阵,需要额外花费3个单位来实现所有点的连通。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【题目描述】

有一个MM行NN列的点阵,相邻两点可以相连。一条纵向的连线花费一个单位,一条横向的连线花费两个单位。某些点之间已经有连线了,试问至少还需要花费多少个单位才能使所有的点全部连通。

【输入】

第一行输入两个正整数mm和nn。

以下若干行每行四个正整数x1,y1,x2,y2x1,y1,x2,y2,表示第x1x1行第y1y1列的点和第x2x2行第y2y2列的点已经有连线。输入保证|x1−x2|+|y1−y2|=1|x1−x2|+|y1−y2|=1。

【输出】

输出使得连通所有点还需要的最小花费。

【输入样例】

2 2
1 1 2 1

【输出样例】

3

【提示】

【数据规模】

30%数据:n×m≤1000n×m≤1000;

100%数据:m,n≤1000m,n≤1000。

官方说不上图片要限流(bushi

思路:这道题比较特殊,由于横向和纵向的边权值分别是一样的,由此根据kruskal的原理先逐一遍历纵向的后再逐一遍历横向的即可,至于已经有的直接加在并查集里表示联通即可,后面遍历到不可能再加一遍的。AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
//并查集 
int fa[maxn];
void make()
{
	iota(fa,fa+maxn,0);
}
int find(int x)
{
	return fa[x]==x?x:fa[x]=find(fa[x]);
}
bool same(int a,int b)
{
	return find(a)==find(b);
}
void unite(int a,int b)
{
	a=find(a);
	b=find(b);
	fa[a]=b;
}
//------------------------------------------------
int n,m,sum=0;//n行m列 
void read()
{
	cin>>n>>m;
	int x1,y1,x2,y2;
	while(cin>>x1>>y1>>x2>>y2)
	{
		x1--;y1--;x2--;y2--;
		unite(x1*m+y1,x2*m+y2);
	}
}
void kruskal()
{
	for(int i=0;i<n-1;i++)
	{
		for(int j=0;j<m;j++)
		{
			if(same(i*m+j,(i+1)*m+j));
			else
			{
				unite(i*m+j,(i+1)*m+j);
				sum++;
			}
		}
	}
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<m-1;j++)
		{
			if(same(i*m+j,i*m+j+1));
			else
			{
				unite(i*m+j,i*m+j+1);
				sum+=2;
			}
		}
	}
}
int main()
{
	ios_base::sync_with_stdio(false),cin.tie(nullptr);
	make();
	read();
	kruskal();
	cout<<sum;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值