刚开始用的是quick-select选取第N - 1小的边,感觉挺有道理的,没有意识到前N-1小的边可能会构成环。所以这道题还是要求最小生成树,然后里面的边就保证能够将所有的点都连接起来。最小生成树里面最大的那条边即为所求。
2485 | Accepted | 788K | 235MS | C++ | 2953B |
/*
ID: thestor1
LANG: C++
TASK: poj2485
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <limits>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <cassert>
using namespace std;
int quickselect(vector<int> &dis, int k)
{
int left = 0, right = dis.size() - 1;
int pivot;
while (left <= right)
{
pivot = dis[left];
int i = left + 1, j = right;
while (true)
{
while (i <= right && dis[i] <= pivot)
{
i++;
}
while (dis[j] > pivot)
{
j--;
}
if (i < j)
{
int tmp = dis[i];
dis[i] = dis[j];
dis[j] = tmp;
i++;
j--;
}
else
{
break;
}
}
int tmp = dis[left];
dis[left] = dis[j];
dis[j] = tmp;
if (j - left + 1 == k)
{
return pivot;
}
else if (j - left + 1 < k)
{
k -= j - left + 1;
left = j + 1;
}
else
{
right = j - 1;
}
}
assert (false);
return -1;
}
void makeset(const int N, std::vector<int> &parent, std::vector<int> &rank)
{
for (int u = 0; u < N; ++u)
{
parent[u] = u;
rank[u] = 0;
}
}
int find(int u, std::vector<int> &parent)
{
if (parent[u] != u)
{
parent[u] = find(parent[u], parent);
}
return parent[u];
}
void union_set(int u, int v, std::vector<int> &parent, std::vector<int> &rank)
{
int ru = find(u, parent);
int rv = find(v, parent);
if (ru == rv)
{
return;
}
if (rank[ru] < rank[rv])
{
parent[ru] = rv;
}
else if (rank[rv] < rank[ru])
{
parent[rv] = ru;
}
else
{
parent[ru] = rv;
rank[rv]++;
}
}
class Edge
{
public:
int u, v, w;
Edge() {}
Edge(int u, int v, int w) : u(u), v(v), w(w) {}
bool operator< (const Edge &rhs) const
{
if (this->w != rhs.w)
{
return this->w < rhs.w;
}
return this->u < rhs.u || (this->u == rhs.u && this->v < rhs.v);
}
};
int kruskal(const int N, std::vector<Edge> &edges)
{
std::vector<int> parent(N);
std::vector<int> rank(N);
makeset(N, parent, rank);
sort(edges.begin(), edges.end());
// int mst = 0;
int n = 0;
for (int i = 0; i < edges.size(); ++i)
{
Edge edge = edges[i];
if (find(edge.u, parent) != find(edge.v, parent))
{
// mst += edge.w;
n++;
union_set(edge.u, edge.v, parent, rank);
if (n == N - 1)
{
return edge.w;
}
}
}
assert (false);
return -1;
}
int main()
{
int T;
scanf("%d", &T);
for (int t = 0; t < T; ++t)
{
int N;
scanf("%d", &N);
std::vector<Edge> edges;
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < N; ++j)
{
int d;
scanf("%d", &d);
if (i < j)
{
edges.push_back(Edge(i, j, d));
}
}
}
int mst = kruskal(N, edges);
cout << mst << endl;
}
return 0;
}