题意:
给出N个城镇的坐标和M条已经建好的路, 求连接所有城镇且长度之和最小的高速公路系统的每条公路, 已经存在的公路不用输出。
样例:
Sample Input
9 (城镇个数及坐标)
1 5
0 0
3 2
4 5
5 1
0 4
5 2
1 2
5 3
3 //M条已建好的路,城镇1-->3,9--->7,1--->2
1 3
9 7
1 2
Sample Output
1 6
3 7
4 9
5 7
8 3
由于最后不用输出长度值, 而且坐标的绝对值不超过10000, 所以在算城镇距离的时候就直接省去了sqrt(),由于需要输出MST的边, 所以开了preVex[]记录每个结点的前驱结点, 默认值都为1. 每次选到新的扩展结点min_i后, 若连接它的边权值不为-1, 即这条路是新修建的, 则输出这条边. 然后如果min_i到MST外的某一结点i的权值, 比MST中其它结点到i的权值还要小, 那么更新dis[1][i]): dis[1][i]=dis[min_i][i], 然后顺带更新preVex[i]为min_i.
import java.util.Scanner;
public class Main{
private int dis[][];//邻接矩阵
private int n;//城镇的个数
private boolean vis[]; //城镇已加入到MST的标志
public Main(int n,int[][] dis){
this.n=n;
this.dis=dis;
vis=new boolean[n+1];
}
static int DIS(int x1,int y1,int x2,int y2){//计算两城镇的距离(权)
return ((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
private void prim(){
int preVex[]=new int[n+1];
vis[1]=true; //城镇1已加入到MST
for(int i=1;i<=n;i++) preVex[i]=1;
for(int k=1;k<n;k++){
int min_i=1;
int min = Integer.MAX_VALUE;
for(int i=1;i<=n;i++){
if(!vis[i] &&dis[1][i]<min) {
min=dis[1][i];
min_i=i;
}
}
vis[min_i]=true; //城镇min_i已加入到MST
if(dis[1][min_i]!=-1) System.out.printf("%d %d\n",preVex[min_i],min_i);
for(int i=1;i<=n;++i)
if(!vis[i] && dis[min_i][i]<dis[1][i]){
dis[1][i]=dis[min_i][i];
preVex[i]=min_i;
}
}
}
public static void main(String[] args){
Scanner in=new Scanner(System.in);
int n=in.nextInt();
int[][] dis=new int[n+1][n+1];
int x[]=new int[n+1];
int y[]=new int[n+1];
for(int i=1;i<=n;i++){//n个城镇的坐标
x[i]=in.nextInt();
y[i]=in.nextInt();
}
int m=in.nextInt();//m条已建好的公路
int u,v;
for(int i=1;i<=m;++i){
u=in.nextInt();
v=in.nextInt();
dis[u][v]=dis[v][u]=-1; //城镇u与v之间已有公路,他们的距离设为-1,必进最小生成树
}
for(int i=1;i<n;++i) {
for(int j=i+1;j<=n;++j)
if(dis[i][j]==0)
dis[j][i]=dis[i][j]=DIS(x[i],y[i],x[j],y[j]);
}
new Main(n,dis).prim();
}
}