Xiao Xieのエンジニアリングタスク(30ポイント)
Xiao Xieは、2次元の惑星に住むために引っ越したばかりのエンジニアです。今、彼は惑星上の村への道を開くつもりです。村にはn
、必要な場所(から1
までの番号が付けられてn
います)があることが規定されています。舗装されており、n
場所が任意の2つの場所にあることを確認する必要があるだけです(つまり、接続されたグラフ)。ただし、それらは2次元の惑星上にあり、各場所は2つの上の点として抽象化されているためです。次元座標系で(a,b)
は、任意の2つの場所を接続するコストは、ヨーロッパのコストと同じではなくなりました。マイルの距離は関連しています。場所A(x,y)
、場所B(p,q)
、これら2つの場所の間の道路を舗装するコストが規定されているとしmin(∣x−p∣,∣y−q∣)
ます。これは新参のXiao Xieにとっては少し難しいです。彼が地図を提供したので、彼が最小のコストでプロジェクトを計画するのを手伝うことができます。 。これらのn個の場所の2つのポイントは接続されていますか?
入力フォーマット:
最初の行は、場所の数を表す整数nを出力します(2 <= n <= 100000)
次のn行では、各行に2つの整数x、yが含まれています。2次元座標系でi番目の村の座標(x、y)を表します。(0 <= x、y <= 1000000)
出力フォーマット:
プロジェクトの最小コストを表す整数を出力します。
入力サンプル:
3
1 1
5 6
2 3
サンプル出力:
4
説明例:
第一个地点和第三个地点铺设道路,代价为 min(|1-2|,|1-3|) = 1;
第二个地点和第三个地点铺设道路,代价为 min(|2-5|,|3-6|) = 3;
此时三个地点已构成任意两点连通并且满足最小代价;
总的最小代价为4。
問題解決:
このトピックでは、グラフのすべての頂点を接続する必要があり、最小のコストで、最小スパニングツリーの問題を考えることができます。最初に、頂点をxで大きいものから小さいものに並べ替えて、グラフにエッジを挿入します。頂点は、グラフにエッジを挿入するために、大きいものから小さいものへとyでソートされます。必要な最小スパニングツリーを見つけるには、上記の2つの方法で挿入されたエッジ上に構築する必要があるため、グラフをトラバースして最小スパニングツリーを見つけます。ここでn <= 1e5の場合、マトリックスを使用するとグラフの時間と空間が爆発することに注意してください。
コードは次のとおりです。
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int maxn = 1e5 + 2;
int ans;
#pragma region 并查集
int Set[maxn];
int FindSet(int x) {
if (Set[x] < 0) return x;
return Set[x] = FindSet(Set[x]);
}
bool UnionSet(int r1, int r2) {
if (r1 == r2) return false;
if (Set[r1] < Set[r2])
Set[r1] += Set[r2], Set[r2] = r1;
else
Set[r2] += Set[r1], Set[r1] = r2;
return true;
}
#pragma endregion
#pragma region 邻接表图
typedef struct ENode {
int v1, v2, w;
} * Edge;
struct AdjVNode {
int AdjV;
AdjVNode* Next;
};
typedef struct VNode {
AdjVNode* FirstEdge;
} AdjVList;
typedef struct GNode {
int Nv, Ne;
AdjVList L[maxn];
} * Graph;
void InsertEdge(Edge E, Graph G) {
AdjVNode* A;
A = new AdjVNode();
A->AdjV = E->v2;
A->Next = G->L[E->v1].FirstEdge;
G->L[E->v1].FirstEdge = A;
A = new AdjVNode();
A->AdjV = E->v1;
A->Next = G->L[E->v2].FirstEdge;
G->L[E->v2].FirstEdge = A;
}
void Dispose(Graph G) {
AdjVNode* A;
for (int i = 0; i < G->Nv; i++) {
while (G->L[i].FirstEdge) {
A = G->L[i].FirstEdge;
G->L[i].FirstEdge = A->Next;
delete A;
}
}
delete G;
G = NULL;
}
#pragma endregion
#pragma region 优先队列
struct cmp {
bool operator()(const ENode& E1, const ENode& E2) {
return E1.w > E2.w; }
};
priority_queue<ENode, vector<ENode>, cmp> q;
#pragma endregion
struct node {
// 点
int x, y;
int id;
} P[maxn];
int getvalue(node A, node B) {
return min(abs(A.x - B.x), abs(A.y - B.y)); }
bool cmp1(node A, node B) {
return A.x < B.x; }
bool cmp2(node A, node B) {
return A.y < B.y; }
void MinTree(Graph G) {
while (!q.empty()) {
int v1 = q.top().v1;
int v2 = q.top().v2;
int w = q.top().w;
q.pop();
if (UnionSet(FindSet(v1), FindSet(v2))) ans += w;
}
}
int main() {
memset(Set, -1, sizeof(Set));
int n, x, y;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> P[i].x >> P[i].y;
P[i].id = i;
}
Graph G = new GNode();
G->Nv = n;
Edge E = new ENode();
sort(P, P + n, cmp1);
for (int i = 1; i < n; i++) {
E->v1 = P[i].id, E->v2 = P[i - 1].id;
E->w = getvalue(P[i], P[i - 1]);
InsertEdge(E, G);
q.push({
E->v1, E->v2, E->w});
}
sort(P, P + n, cmp2);
for (int i = 1; i < n; i++) {
E->v1 = P[i].id, E->v2 = P[i - 1].id;
E->w = getvalue(P[i], P[i - 1]);
InsertEdge(E, G);
q.push({
E->v1, E->v2, E->w});
}
delete E;
MinTree(G);
Dispose(G);
cout << ans << endl;
system("pause");
return 0;
}