題解:UVa1025 A Spy in the Metro
阿新 • • 發佈:2018-05-12
cit %d mat png a10 direct 發現 TP 最小 pdf
不是瓶頸生成樹,那麽我們找到該最小生成樹的權值最大邊\(e\),我們選取該圖中的一顆瓶頸生成樹\(T_1\),則有:對於\(T_1\)中的任何邊\(e_1\),存在\(V_{e_1} <V_{e}\)。刪除\(T\)中的\(e\),我們得到兩棵樹\(T_a,T_b\)。由於\(T_1\)是一顆生成樹,必有一條邊\(e_{ab}\)連接\(T_a,T_b\),用\(e_{ab}\)替換\(e\),可以得到更小的生成樹,與\(T\)是最小生成樹矛盾。證畢。
原題鏈接
題目大意
給出一張無向圖圖,求該圖的最小瓶頸生成樹。
無向圖的瓶頸生成樹:無向圖\(G\)的一顆瓶頸生成樹是這樣的一顆生成樹:它最大的邊權值在\(G\)的所有生成樹中是最小的。瓶頸生成樹的值為\(T\)中最大權值邊的權。
該圖建立在坐標系中, 給出每個點的坐標。任意兩點之間都有邊,邊權即為兩點間的距離。
題解
由於只關心生成樹的最大值,我們可以將邊從小到大排序,依次加入(若構成環則不加入),直到構成一顆生成樹。
相信你已經發現了:這不就是Kruskal算法嗎?
於是,我們得出結論:無向圖的最小生成樹一定是瓶頸生成樹。
如果你仍然感到懷疑,那麽我們再用反證法證明:
假設存在一張無向圖的最小生成樹\(T\)
順便提一句,無向圖瓶頸生成樹一定是最小生成樹嗎?
看一看下圖就知道了:
由於本題是稠密圖,最好用Prim解決(然而懶到家的我還是用了Kruskal)。
聽說有一種復雜度更優的算法叫Camerini‘s algorithm(然而我並不會),如果有大神會的話也可以教導我一下。
代碼
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn = 5005;
struct City
{
double x, y;//註意是小數(開float似乎也行)
} city[maxn];
struct Edge
{
int from, to;
double dist;
bool operator < (const Edge& other) const
{
return dist < other.dist;
}
} edge[maxn*maxn];
int n, m, S;
inline double sqr(double a)
{
return a*a;
}
inline double make_dist(City a, City b)
{
return sqrt(sqr(a.x-b.x) + sqr(a.y-b.y));
}
inline void add_edge(City a, City b, int ai, int bi)
{
double dist = make_dist(a, b);
m++;
edge[m].from = ai;
edge[m].to = bi;
edge[m].dist = dist;
}
inline void read()
{
scanf("%d%d", &S, &n);
S = n-S;
for(int i = 1; i <= n; ++i)
{
scanf("%lf%lf", &city[i].x, &city[i].y);
for(int j = 1; j < i; ++j)
add_edge(city[i], city[j], i, j);
}
}
struct UN_set
{
int fa[maxn];
inline void init(int n)
{
for(int i = 1; i <= n; ++i)
fa[i] = i;
}
inline int getfa(int x)
{
return fa[x] == x ? x : fa[x] = getfa(fa[x]);
}
} un;
inline double Kruskal()//其實最好還是用prim
{
int tmp = 0;
m = 0;
read();
sort(edge+1, edge+m+1);
un.init(n);
for(int i = 1; i <= m; ++i)
{
int ff = un.getfa(edge[i].from);
int tf = un.getfa(edge[i].to);
if(ff != tf)
{
un.fa[ff] = tf;
tmp++;
if(tmp == S)
return edge[i].dist;
}
}
return -1;
}
int main()
{
int nnn;
scanf("%d", &nnn);
while(nnn--)
printf("%.2f\n", Kruskal());//直接求最小生成樹即可
return 0;
}
題解:UVa1025 A Spy in the Metro