Freckles(并查集)

In an episode of the Dick Van Dyke show, little Richie connects the freckles (on his Dad’s back )(to form a picture )(of the Liberty Bell.)

在DBDshow的剧情,小R连接这些点  在父亲的背上  to形成一个图片of 自由钟

Alas, one of the freckles turns out to be a scar, so his Ripley’s engagement falls through.

其中一个点变成了伤疤,所以他的  **(投入?) 失败了

Consider Dick’s back to be a plane with freckles at various (x,y) locations.

考虑D的后背 成一个平面,带着xy坐标

Your job is to tell Richie how to connect the dots so as to minimize the amount of ink used.

你的工作是告诉R  如何连接这些点,使用最少的墨水

Richie connects the dots by drawing straight lines between pairs, possibly lifting the pen between lines.

R连接这些点 通过两点直连, 可能在线之间抬笔(?)

When Richie is done there must be a sequence of connected lines from any freckle to any other freckle

当工作结束,必须一系列的线,任意两点连接好)

输入:
The first line contains 0 < n <= 100, the number of freckles on Dick’s back.

For each freckle, a line follows;

each following line contains two real numbers indicating the (x,y) coordinates of the freckle.
输出:
Your program prints a single real number to two decimal places: the minimum total length of ink lines that can connect all the freckles.
样例输入:
3
1.0 1.0
2.0 2.0
2.0 4.0
样例输出:
3.41

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <map>
#include <stack>
#include <iomanip>
using namespace std;



typedef struct Dot {
	double x, y;
} Dot;


typedef struct Edge {
	int u, v; // 起始坐标 结束坐标
	double len; // 长度 距离
} Edge;


bool compare(Edge& a, Edge& b) {
	return a.len <= b.len;
}


// ok
double getDistance(Dot& a,Dot& b) {
	// a:(x1,y1)   b:(x2,y2)
	// (x2 - x1)^2 +  (y2 - y1) ^2
	// 开根号
	double result = pow((b.x - a.x),2) + pow((b.y - a.y),2);
	result = sqrt(result);
	return result;
}

class UnionFind {
		int father[101]; // 1 ~ 100  记录上级/老大
		int contain[101]; // 包含多少小弟
		int minIndex; // 范围
		int maxIndex; // 范围
		int cnt; //连通分量的个数

	public :
		UnionFind() {}
		UnionFind(int minIndex, int maxIndex) {
			// 1 ~ 4
			this->minIndex = minIndex;
			this->maxIndex = maxIndex;
			this->cnt = maxIndex - minIndex + 1; // 连通分量的个数

			for (int i = minIndex; i <= maxIndex ; i++) {
				father[i] = -1;
				contain[i] = 1;
			}

		}

		int getRoot(int x) {
			if (father[x] == -1) {
				return x;  // 自己就是老大
			} else {
				//自己不是老大,自己有上级
				// 上级是set老大 还是 图上的父节点?
				int d = father[x];
				int root = getRoot(d);
				if (d != root) {
					father[x] = root; // 直接跟root算了,不跟图上的父节点
					contain[d] -= contain[x]; // contain少了,投奔root了
				}
				return root;
			}
		}

		bool isConnected(int x, int y) {
			return getRoot(x) == getRoot(y);
		}

		bool connect(int x, int y) {
			//	cout << "目前正在连接" << x << " " << y << endl;
			int xRoot = getRoot(x);
			int yRoot = getRoot(y);
			//	cout << "根:" <<  xRoot << "and" << yRoot << endl;
			if (xRoot == yRoot) {
				return false; // 已经在同一个set里面了,已经在同一个连通分量里面了
			} else {
				//		cout << x << " " << y << "可以连接" <<endl;
				if(contain[x] >= contain[y]) {
					// x 人多势大, y投奔x
					father[yRoot] = xRoot;
					contain[xRoot] += contain[yRoot];
				} else {
					// y人多势大,x投奔y
					father[xRoot] = yRoot;
					contain[yRoot] += contain[xRoot];
				}
			}
			cnt --; //连通分量少1
		}

		int getCnt() {
			return cnt;
		}

		void show() {
			cout << "---目前情况---" << endl;
			cout << "father :";
			for (int i = minIndex; i <= maxIndex; i++) {
				cout << setw(4) << father[i] << "\t";
			}
			cout << endl;

			cout << "index  :";
			for (int i = minIndex; i <= maxIndex; i++) {
				cout << setw(4)  << i << "\t";
			}
			cout << endl << endl;


			cout << "contain :";
			for (int i = minIndex; i <= maxIndex; i++) {
				cout << setw(4)  << contain[i] << "\t";
			}
			cout << endl;

			cout << "index  :";
			for (int i = minIndex; i <= maxIndex; i++) {
				cout << setw(4)  << i << "\t";
			}
			cout << endl;

			cout << "---打印完毕---" << endl << endl;
		}

		void print(vector<Edge> edges) {
			cout << "目前edges的vector:" << endl;
			for (int i = 0; i <= edges.size() - 1; i++) {
				cout << edges[i].u << " " << edges[i].v << " " << edges[i].len << endl;
			}
			cout << "**打印完毕" << endl;
		}

		double mst(vector<Edge> edges) {
			double sum = 0;
			sort(edges.begin(), edges.end(), compare);
//				print(edges);
			for (int i = 0; i <= edges.size() - 1; i++) {
				int u = edges[i].u;
				int v = edges[i].v;
				bool flag = connect(u, v);
				//	cout << "***" << sum << endl;
				if (flag) {
					sum += edges[i].len;
					//		cout << "***" << sum << endl;
					if (getCnt() == 1) {
						return sum;
					}
				} else {
					//		cout << "***" << "no!" << endl;
					continue;
				}
			}
			return -1;
		}

};


int main() {

	int n;
	while (cin >> n && n != 0) {
		if (n == 1) {
			cout << "0" << endl;
		} else {

			vector<Dot> dots;
			vector<Edge> edges;
			UnionFind uf(0,n-1); // 一共有n个点,编号: 0 ~ n-1

			Dot dot;
			for (int i = 0; i <= n - 1; i ++) {
				cin >> dot.x >> dot.y;
				dots.push_back(dot); // dots[0] 就是 0点  // 找具体的点的x、y 就找dots[i].x y
			}

			Edge edge;
			for (int i = 0; i <= dots.size() - 1; i++) {
				for (int j = i + 1; j <= dots.size() - 1; j++) {
					edge.u = i;
					edge.u = j; // 0点到1点
					edge.len = getDistance(dots[i],dots[j]);
					edges.push_back(edge);
				}
			}


			double sum = uf.mst(edges);
			printf("%.2f",sum);
		}
	}

	return 0;
}



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值