思路:
求最小生成树的时候记录下每一条边,然后逆序排序,然后跳出第s的边,相当于前(s-1)大的边免费。
Arctic Network
Prim算法:
Solution1:
#include<stdio.h>
#include<iostream>
#include<cmath>
#include<math.h>
#include<string>
#include<string.h>
#include<algorithm>
#define ll long long
using namespace std;
const int size=500+5;
double a[size][size];
double pos_max_cost[size],w[size];
int n,m,cnt; //a为邻接矩阵
bool v[size];
struct Dot {
int x,y;
}dots[size];
double get_dis(Dot a,Dot b){
int dx = a.x-b.x,dy=a.y-b.y;
return sqrt(dx*dx+dy*dy);
}
void prim(){
cnt=0;
memset(v, 0, sizeof(v));
w[1]=0;
v[1]=1;
//初始化cost数组
for(int i=2;i<=n;i++){
w[i]=a[i][1];
}
//再加入n-1个点
for(int j=1;j<=n-1;j++){
double mincost= 1<<30;int minid=2;
//找出花费最小的那个点
for(int i=2;i<=n;i++){
if(!v[i] && w[i]<mincost){
mincost=w[i];minid=i;
}
}
pos_max_cost[++cnt]=mincost;
v[minid]=1;
//更新花费数组
for(int i=2;i<=n;i++) w[i]=min(w[i],a[i][minid]);
}
}
int main(){
int t,s,p;
cin>>t;
while(t--){
cin>>s>>p;
n=p;
for(int i=1;i<=p;i++){
int x,y;
scanf("%d%d",&x,&y);
dots[i].x=x;dots[i].y=y;
}
for(int i=1;i<p;i++){
for(int j=i+1;j<=p;j++){
a[i][j]=a[j][i] = get_dis(dots[i], dots[j]);
}
}
prim();
sort(pos_max_cost+1,pos_max_cost+p);
reverse(pos_max_cost+1, pos_max_cost+p);
printf("%.2f\n",pos_max_cost[s]);
}
return 0;
}
Solution2:
Kruskal算法
#include<stdio.h>
#include<iostream>
#include<math.h>
#include<string>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=800; //数组要开够
int n,m,bm,fa[maxn],ncase,s;
double cost[maxn+5];
struct Dot{
int x,y;
}dots[maxn];
struct Edge{
int u,v;
double cost;
}t[maxn*maxn/2];
double get_dis(int i,int j){
double dx=dots[i].x-dots[j].x;
double dy=dots[i].y-dots[j].y;
return sqrt(dx*dx+dy*dy);
}
bool cmp(Edge a,Edge b){
return a.cost<b.cost;
}
int find(int x){
return (x==fa[x])?x:fa[x]=find(fa[x]);
}
void merge(int x,int y){
fa[find(x)]=find(y); //合并代表元
}
void init()
{
for(int i=1;i<=n;i++) fa[i]=i;
memset(cost,0,sizeof(cost));
}
int main(){
cin>>ncase;
while(ncase--)
{
cin>>s>>n;
//初始化点集
for(int i=1;i<=n;i++){
int x,y;
scanf("%d%d",&x,&y);
dots[i].x=x;dots[i].y=y;
}
m=0;//初始化边集
for(int i=1;i<n;i++){
for(int j=i+1;j<=n;j++){
t[++m].u=i;t[m].v=j;
t[m].cost=get_dis(i, j);
}
}
//初始化并查集
init();
sort(t+1,t+m+1,cmp);
int cnt=0;
//已经建好的,直接merge就好
for(int i=1;i<=m;i++){
int u=t[i].u,v=t[i].v;
if(find(u)!=find(v)){
merge(u,v);
cost[++cnt]=t[i].cost;
}
}
sort(cost+1, cost+n);
reverse(cost+1, cost+n);
printf("%.2f\n",cost[s]);
}
return 0;
}
完全图的最小生成树还是用prim算法好啊。