P2872
最初の
トピックを要約したものです。タイトルは、私たちは長い道のりを構築するために必要なすべてのChina Unicomある牧場を作るしようとしています。
明らかに、このボードは(初心者のために何を推奨)最小全域木問題です。
その後、私は約それをクラスカル言います。
クラスカル法は1956年にジョセフ・クラスカルによって公開最小スパニングツリーアルゴリズムを、見つけるために使用する方法です。
同じ問題だけでなく、プリム法とBoruvkaアルゴリズムを解決するには。3つのアルゴリズムは、貪欲アルゴリズムのアプリケーションです。
場所と異なるアルゴリズムBoruvka、同じことが有効であるとき、エッジの重みダイアグラム上クラスカル法。------- Baiduの百科事典から来ています
まず、基本的な考え方
クラスカルは、チェックポイントの各組の右側、使用およびメンテナンスに応じて貪欲考え、各エッジ配列における最初の行を利用します。
それも側に説明する必要がなかった場合は最初の2点は、内部コレクションにないと判断された場合クラスカルを実行します。
カウンタレコードプラスエッジの数に従事し、記録時に右サイドをマージ。
我々は、すべてのマップがある場合ことを知っている\(N \)のノードは、最小の\(N-1 \)はエッジがこのチャートユニコムそれを行うことができます。
その後、我々は覚えておくことは、カウンタのカウントを待つことができます\(N-1 \) (正のソリューションとなっている)の実行を停止する時間を。
それ以来、この\(N-1 \)は、図にエッジは、その後明らかに、一緒に結合- (Mする\ n)\。エッジが図にm個の部分に分割することができる(グッドアヒルのような)例を:. P1195を
第二に、コード
for (int i = 1; i <= cnt; i++) {
if (father(edge[i].x) != father(edge[i].y)) {//判断是不是在一个集合中
f++;
unionn(edge[i].x, edge[i].y);//合并
ans += edge[i].dis;//记录总权值
}
if (f == m) break;//如果做完了,那就停下啊.
}
この問題はコードやアイデア:
いくつかの側面がありますのでそこ始まりであり、それらの側はその後、我々はすぐそこが0に割り当てられて起動し、十分なクラスカル実行し続けることができます。
座標を与えられたので、最初にすべてを貯め座標、その後、または2を構築するための2つの辺の間のユークリッド距離に応じて、これらの座標を置きます。
ユークリッド距離の式:\(\ SQRT {((X_ {-x_ 1} {2})*(X_ {-x_ 1} {2})+(-y_ Y_ {{2}} 1)*(。。 Y_ {1} -y_ {2} ))} \)
#include <bits/stdc++.h>
#define N 1000010
#define M 2010
using namespace std;
int fath[M], n, m; bool b[M];
double px[M], py[M];
struct node {//结构体存边.
int x, y;
double dis;
}edge[N << 2];
int read() {
int s = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
int father(int x) {
if (x != fath[x]) fath[x] = father(fath[x]);//求是不是在一个集合里
return fath[x];
}
void unionn(int x, int y) {
int fx = father(x), fy = father(y);//合并两个集合
fath[x] = fath[y];
}
bool cmp(node p, node q) {
return p.dis < q.dis;//sort用品
}
int main() {
n = read(), m = read();
int z = n + m;//原本就有的
for (int i = 1; i <= z; i++) fath[i] = i;
int cnt = 0;
for (int i = 1, x, y; i <= n; i++) {
x = read(), y = read();
px[i] = x, px[i] = y;//因为给出的是坐标,先把坐标存起来.
}
for (int i = 1; i <= n; i++) fath[i] = 1;
for (int i = n + 1, x, y; i <= n + m; i++) {
x = read(), y = read();
px[i] = x, py[i] = y;
}
for (int i = 1; i <= n + m; i++) {
for (int j = i + 1; j <= n + m; j++) {//开始存边
cnt++;
edge[cnt].x = i;
edge[cnt].y = j;
edge[cnt].dis = sqrt((px[i] - px[j]) * (px[i] - px[j]) + (py[i] - py[j]) * (py[i] - py[j]));
}
}
sort(edge + 1, edge + cnt + 1, cmp);//给边排一下序
int f = 0;
double ans = 0;
for (int i = 1; i <= cnt; i++) {//kruskal
if (father(edge[i].x) != father(edge[i].y)) {
f++;
unionn(edge[i].x, edge[i].y);
ans += edge[i].dis;
}
if (f == m) break;
}
printf("%.2lf", ans);
}