kruskai,贪心
题意:
分析:
这一题我是由kruskai算法为突破口的。
我们想想,对于一揽子的节点,我们要对他们进行并查集操作,将其合成k个集合。
然后求集合间的最短距离。我们想 让这个最短距离尽量大!
由kruskai算法作为突破口,我们不妨对所有的边按照其权值从小到大排序。
边:共有n*n-n个,权值为距离。
然后贪心的从距离最小的边开始进行合并,直到合成k个集合。也就是执行kruskai算法操作。
最后,遍历剩下的边,找到最小距离。
为什么可以这样贪心呢?
因为,我们最终是要形成k个集合的对吧。那么我们为什么不尽量用距离小的边去形成k个集合呢?
如果我们对于一个距离为1的边放着不用,去用一个距离为2的边的话,距离为1的边就有可能成最短边了!
贪心是成立的。
kruskai算法!!!
代码如下,我直接使用我的kruskai算法板子了
#include<iostream> #include<algorithm> #include<vector> #include<iomanip> using namespace std; typedef long long ll; typedef pair<int, int>pii; const int max_n = 1100; int n, k; vector<pii> points; struct edge { int u, v, next; ll cost; }E[max_n * max_n]; int head[max_n]; int cnt = 1; void add(int from, int to,ll cost) { E[cnt].u = from; E[cnt].v = to; E[cnt].cost = cost; E[cnt].next = head[from]; head[from] = cnt++; } int par[max_n]; int rak[max_n]; void init() { points.clear(); fill(head, head + 1 + n, false); fill(rak, rak + 1 + n, 0);cnt = 1; for (int i = 0;i <= n;i++)par[i] = i; k = n - k; } int find(int x) { return x == par[x] ? x : par[x] = find(par[x]); } bool same(int x, int y) { return find(x) == find(y); } bool merge(int u, int v) { u = find(u);v = find(v); if (u == v)return false; if (rak[u] > rak[v])par[v] = u; else if (rak[v] > rak[u])par[u] = v; else par[v] = u, rak[u]++; return true; } bool cmp(edge& e1, edge& e2) { return e1.cost < e2.cost; } double kruskai() { int i; sort(E + 1, E + 1 + cnt-1, cmp); for (i = 1;i <= cnt-1 && k;i++) { int u = E[i].u;int v = E[i].v; if (merge(u, v)) k--; } for (;i <= cnt - 1;i++) if (!same(E[i].u, E[i].v)) return sqrt(E[i].cost); return 0; } ll compute(ll x1, ll y1, ll x2, ll y2) { return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); } int main() { ios::sync_with_stdio(0); cin >> n >> k;init(); for (int i = 1;i <= n;i++) { int x, y;cin >> x >> y; points.push_back({ x,y }); }for (int i = 0;i < n;i++) { int x1 = points[i].first; int y1 = points[i].second; for (int j = i + 1;j < n;j++) { int x2 = points[j].first; int y2 = points[j].second; ll cost = compute(x1, y1, x2, y2); add(i + 1, j + 1, cost);add(j + 1, i + 1, cost); } } cout << fixed << setprecision(2) << kruskai() << endl; }