ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

GDUT_专题三:F - Built?

2022-02-04 13:03:51  阅读:208  来源: 互联网

标签:dian GDUT 专题 return Built int ll between include


题目:

There are towns on a plane. The -th town is located at the coordinates . There may be more than one town at the same coordinates.Ni(xi​,yi​)

You can build a road between two towns at coordinates and for a cost of yen (the currency of Japan). It is not possible to build other types of roads.(a,b)(c,d)min(|a-c|,|b-d|)

Your objective is to build roads so that it will be possible to travel between every pair of towns by traversing roads. At least how much money is necessary to achieve this?

Constraints

  • 2 ≤ N ≤ 10^5
  • 0≤xi​,yi​≤10^9
  • All input values are integers.

Input

Input is given from Standard Input in the following format:

N
x1​ y1​
x2​ y2​
:
xNyN

Output

Print the minimum necessary amount of money in order to build roads so that it will be possible to travel between every pair of towns by traversing roads.

Sample 1

InputOutput
3
1 5
3 9
7 8
3

Build a road between Towns 1 and 2, and another between Towns 2 and 3. The total cost is 2+1=3 yen.

Sample 2

InputOutput
6
8 3
4 9
12 19
18 1
13 5
7 6
8

 题意:

给你在二维坐标上的N个点,你可以连接任意两点(a,b)(c,d),花费价值为 min(|a-c|,|b-d|)。求所有点连通的最小花费价值。

思路分析:

看题意就是一道最小生成树的问题,但是这题的难点在于如何建图,平常的建图都是一个值代表一个图的结点,但是题目里直接给出了,一个二维的坐标,并且权值各有两种可能,若想先求出所有边权的可能再去建图,时间复杂度无疑太高了。因此我们为了找到差值最小的情况,便可以进行排序,并依照输出的顺序给每个点做标记,分别对x坐标和y坐标分别排序并记录边权最后再对全部的边进行排序使用kruskal算法实现最小生成树。

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<set>
#define IL inline
typedef long long ll;
using namespace std;
//kruskal算法 
const int N = 1e5 + 10;
ll n,ans,sum;
struct edge {//记录边的结构体,p1,p2分别记录转换成结点的图,d表示为边的权值 
	ll p1, p2, d;
} p[2*N];
struct dian {//记录点的结构体 ,以下标id表示为图的结点 
	ll x, y, id;
} a[N];
bool cmpx(dian a, dian b) {//对x坐标排序 
	return a.x < b.x;
}
bool cmpy(dian a, dian b) {//对y坐标排序 
	return a.y < b.y;
}
bool cmp(edge a, edge b) {//对边长坐标排序 
	return a.d < b.d;
}
int f[N];//记录父节点 
int fd(ll x) {//查找父节点 
	if (x == f[x])return x;
	return f[x] = fd(f[x]);
}
void tg(int x, int y) {//合并结点 
	x = fd(x);
	y = fd(y);
	if (x != y)f[y] = x;
}
int kruskal() {//算法实现 
	int num=0;
	for (int i = 1; i <= ans; i++) {
		int x=fd(p[i].p1),y=fd(p[i].p2);
		if(x==y)continue;
		f[x]=y;
		sum+=p[i].d;
		num++;
		if(num==n-1)break;
	}
	return sum;
}
int main() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		scanf("%lld%lld", &a[i].x, &a[i].y);//输入点的坐标 
		a[i].id = i;//记录其为图的结点 
		f[i] = i;//初始化父节点 
	}
	sort(a + 1, a + n + 1, cmpx);//对x排序 
	for (int i = 1; i < n; i++) {//分别记录两个结点的x的所表示边的权值 
		p[++ans].p1 = a[i].id;
		p[ans].p2 = a[i + 1].id;
		p[ans].d = abs(a[i].x - a[i + 1].x);
	}
	sort(a + 1, a + n + 1, cmpy);
	for (int i = 1; i < n; i++) {//分别记录两个结点的y的所表示边的权值 
		p[++ans].p1 = a[i].id;
		p[ans].p2 = a[i + 1].id;
		p[ans].d = abs(a[i].y - a[i + 1].y);
	}
	sort(p+1,p+ans+1,cmp);//对其边的全部权值进行排序 ,转换为了kruskal求最小生成树问题 
	cout<<kruskal()<<endl;
	
	return 0;
}

标签:dian,GDUT,专题,return,Built,int,ll,between,include
来源: https://blog.csdn.net/huanle2565/article/details/122782321

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有