连接格点

题目描述

有一个M行N列的点阵,相邻两点可以相连。一条纵向的连线花费一个单位,一条横向的连线花费两个单位。某些点之间已经有连线了,试问至少还需要花费多少个单位才能使所有的点全部连通。
输入格式 Input Format
第一行输入两个正整数m和n。
以下若干行每行四个正整数x1,y1,x2,y2,表示第x1行第y1列的点和第x2行第y2列的点已经有连线。输入保证|x1-x2|+|y1-y2|=1。

输出格式 Output Format

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

样例输入 Sample Input

2 2
1 1 2 1

样例输出 Sample Output

3

时间限制 Time Limitation

3s

注释 Hint

数据规模

m,n<=1000
来源
matrix67 系列模拟赛

好久没做图论题,心血来潮写一写,我们不难发现,对于一个不存在已有边的矩阵,肯定是连完纵向边,每行连一条横向边这样贪心最优,那么存在已有边时,我们考虑用并查集维护,同时用上述方法贪心,不过我们考虑一下,连完后的图的性质,一定是一条有n * m个点,n * m-1条边的树,同时,这棵树依题意满足权值最小,那么就是一颗最小生成树,再回想刚才的贪心做法,其实和最小生成树无异,那么我们不用费心思去改良之前的贪心,直接用Kurskal算法贪心,跑一边最小生成树。
同时,我们建树时需要手动给点标号,并且标号最大有n*m,所以不能很好地判断自己手动建边时是否存在已有边,因此存在重边,也就是边总数最差为2e6,数组大小记得开够。
当然,个人觉得写一个好一点的哈希似乎还是可以查询的,至于怎么写就要看大佬们的了。
还有,读入的是按m,n读入的,当时没看清,被这个卡了…
在这里插入图片描述

#include<bits/stdc++.h>

#define N 1001
#define gtc() getchar()
#define INF 0x3f3f3f3f
#define rg register
#define MAXN 5000010
#define ll long long

using namespace std;

template <class T>
inline void read(T &s){
	T w = 1, ch = gtc(); s = 0;
	while(!isdigit(ch)){if(ch == '-') w = -1; ch = gtc();}
	while(isdigit(ch)){s = s * 10 + ch - '0'; ch = gtc();}
	s = s * w;
}

struct node{
	int x, y, z;
}d[MAXN];

int n, m, cnt = 0;

inline void add(int x, int y, int z){
	d[++cnt].x = x, d[cnt].y = y, d[cnt].z = z;
}

int fa[MAXN];
inline int getfa(int x){
	return fa[x] == x ? x : fa[x] = getfa(fa[x]);
}

bool cmp(node a, node b){
	return a.z < b.z;
}

inline int point(int x, int y){//计算点的标号用的,手推一下就出来了
	return y + (x-1) * n;
} 

int main()
{
	read(m), read(n);
	int all = n * m;
	for(int i = 1; i <= all; ++i) fa[i] = i;
	
	for(int i = 1; i <= m; ++i)
		for(int j = 1; j <= n; ++j){
			int x = point(i, j), y;
			if(i + 1 <= m){
				y = point(i+1, j);
				add(x, y, 1);
			}
			if(j + 1 <= n){
				y = point(i, j+1);
				add(x, y, 2);
			}
		}
		
	int x, y, xx, yy;
	while(~scanf("%d %d %d %d", &x, &y, &xx, &yy)){
		int tx = point(x, y), ty = point(xx, yy);
		add(tx, ty, 0);
	}

	sort(d + 1, d + cnt + 1, cmp);
	int ans = 0;
	for(int i = 1; i <= cnt; ++i){
		x = d[i].x, y = d[i].y;
		xx = getfa(x), yy = getfa(y);
		if(xx == yy) continue;
		fa[xx] = yy;
		ans += d[i].z;
	}
	
	printf("%d\n", ans);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BIGBIGPPT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值