标签:printf close 最大的 from family namespace targe 最小 names
求一棵最小生成树,要求:忽略树上s-1条边的边权后,最大的边最小。
(因为卫星频道是两两互达的,所以想把连接两个联通块之间的边权忽略必须用两个联通块都放置卫星频道。也就是至少要两个)
emmm...其实我本来想的是分层最短路那种动态规划,记录用了几次忽略机会。
假设已经求出答案最小生成树,忽略边权一定是忽略前s-1大的,那么所求即为第s大的边权。
考虑kruskal算法求最小生成树,每次都选最小的边加入...这样其实就保证了每条边都是当前最小的,那第s大一定也是最小的。
证明?在一棵最小生成树上,用一条非树边代替树边,那么第s大的边的边权要么不变要么变大。(来自学姐)
其实就是裸的最小生成树啊w
代码如下
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #define MogeKo qwq #include<algorithm> using namespace std; const int maxn = 1e6; int t,s,n,cnt,num; int px[maxn],py[maxn],fa[maxn]; struct node { int from,to; double val; bool operator < (const node & N) const { return val < N.val; } } e[maxn]; void add(int a,int b) { e[++cnt].from = a; e[cnt].to = b; e[cnt].val = sqrt( pow(px[a]-px[b],2) + pow(py[a]-py[b],2) ); } int getfa(int x) { if(fa[x] == x)return x; else return fa[x] = getfa(fa[x]); } double kruskal() { for(int i = 1; i <= cnt; i++) { int x = getfa(e[i].from); int y = getfa(e[i].to); if(x == y)continue; fa[x] = y; num++; if(num == n-s)return e[i].val; } } int main() { scanf("%d",&t); while(t--) { scanf("%d%d",&s,&n); cnt = num = 0; for(int i = 1; i <= n; i++) fa[i] = i; for(int i = 1; i <= n; i++) scanf("%d%d",&px[i],&py[i]); for(int i = 1; i <= n; i++) for(int j = i+1; j <= n; j++) add(i,j); sort(e+1,e+cnt+1); printf("%.2lf\n",kruskal()); } return 0; }
标签:printf close 最大的 from family namespace targe 最小 names
原文地址:https://www.cnblogs.com/mogeko/p/10914238.html