最小生成树入门题
题意:有n个点给出坐标,点和点之间可以用无线电或者卫星通信,每个点都有无线电收发器可进行无线电通信,但是只有m个点有卫星通信功能。卫星通信的距离可以无限大,但无线电通信的距离不能超过D,超过D的部分将使通信费用增加。要使通信费用最少。
其实就是求一次最小生成树,m个点有卫星通信,那么就会有m-1条边的通信距离无限大,其实就是这m-1条边不用计算费用。而剩下的边中,找出最大边作为D值,这样剩下的所有的边都不会大于D,那么不会增加通信费用。在构建MST过程中保存下所有的边权值,然后按升序排序,除掉最后的m-1条边(也就是最大的m-1条边,这些边用卫星通信),最大的那条就是D
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define N 510 #define INF 1000000000.000 double g[N][N]; int x[N],y[N]; int n,m; //有m个卫星 double dis(int i ,int j) { return sqrt( 1.*(x[i]-x[j])*(x[i]-x[j])+1.*(y[i]-y[j])*(y[i]-y[j]) ); } void prim() { double lowcost[N],ans[N]; int adj[N],cov[N]; for(int i=2; i<=n; i++) { lowcost[i]=g[1][i]; adj[i]=1; cov[i]=0; } lowcost[1]=0; adj[1]=1; cov[1]=1; for(int nn=1; nn<n; nn++) //还有纳入n-1个点 { double min=INF; int k=1; for(int i=1; i<=n; i++) if(!cov[i] && lowcost[i]<min) { min=lowcost[i]; k=i; } //printf("%.2f\n",min); ans[nn]=min; cov[k]=1; for(int i=1; i<=n; i++) if(!cov[i] && lowcost[i] > g[k][i]) { lowcost[i]=g[k][i]; adj[i]=k; } } sort(ans+1 , ans+n); /* for(int i=1; i<n; i++) printf("%.2f\n",ans[i]); */ printf("%.2lf\n",ans[n-m]); return ; } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d",&m,&n); for(int i=1; i<=n; i++) scanf("%d%d",&x[i],&y[i]); for(int i=1; i<=n; i++) g[i][i]=0; for(int i=1; i<=n; i++) for(int j=i+1; j<=n; j++) g[i][j]=g[j][i]=dis(i,j); prim(); } return 0; }