POJ 1789 最小生成树之prim算法

1、生成树
如果连通图G的一个子图是一棵包含G的所有顶点的树,则该子图称为G的生成树(SpanningTree)。
生成树是连通图的包含图中的所有顶点的极小连通子图,图的生成树不惟一。从不同的顶点出发进行遍历,可以得到不同的生成树。

2、 最小生成树
对于连通的带权图(连通网)G,其生成树也是带权的。生成树T各边的权值总和称为该树的权,权最小的生成树称为G的最小生成树(Minimum SpannirngTree)。最小生成树可简记为MST。

3、MST性质

假设N=(V,{E})是一个连通网,U是顶点集合V的一个非空子集。若(u,v)是一条具有最小值(代价)的边,其中u属于U,v属于V-U(即U对立集合),那么必存在一颗包含边(u,v)的最小生成树。

注意prim和kruskal算法都是利用MST性质

Prim算法求最小生成树的基本思想:

  1.首先选取一个点作为起始点,比如说1顶点,加入到U集合中

2.在所有u∈U,v∈V-U的边(u,v)∈E中,找一条权最小的边(u,v),将此边加进集合T中,并将此边的非U中顶点加入U中。此步骤的功能是在边集E中找一条边,要求这条边满足以下条件:首先边的两个顶点要分别在顶点集合U和V-U中,其次边的权要最小。找到这条边以后,把这条边放到边集T中,并把这条边上不在U中的那个顶点加入到U中。

3:如果U=V,则算法结束;否则重复步骤2。可以把本步骤看成循环终止条件。我们可以算出当U=V时,步骤2共执行了n-1次(设n为图中顶点的数目),TE中也增加了n-1条边,这n-1条边就是需要求出的最小生成树的边。

例:POJ1789

题意:给出n台卡车的条形码(7位字符串),每两台卡车之间的距离为两条条形码相比较相同位置字符不同的个数,让求出包含所有卡车的最小距离。
Sample Input

4
aaaaaaa
baaaaaa
abaaaaa
aabaaaa
0

Sample Output

The highest possible quality is 1/3.

解题: 如果按照上述关系建立图,节点为卡车的编号,边的权值为卡车之间的距离,很容易将本题目变为求一个图的最小生成树问题了。


import java.util.Scanner;
import java.util.Arrays;
public class Main{
private int n; //卡车的数目
private int G[][];//邻接矩阵
String[] s;//n台卡车的条形码

public Main(int n,String s[]){
this.n=n;
this.s=s;
G=new int[n+1][n+1];
init();

}

private int getdis(String s,String t)/* 得到两台卡车之间的而距离 */
{
int tmp=0;
for(int i=0;i<7;i++)
{
if(s.charAt(i)!=t.charAt(i)) tmp++;
}
return tmp;
}

public static void main(String args[]){
Scanner in=new Scanner(System.in);
while(true){
int n=in.nextInt();
if(n==0) break;
String s[]=new String[n+1];
for(int i=1;i<=n;i++)
s[i]=in.next();
Main m=new Main(n,s);
System.out.println("The highest possible quality is 1/"+m.prim()+".");
}


}


private void init(){/* 输入数据 建立邻接矩阵 */
for(int i=1;i<=n;i++){
G[i][i]=Integer.MAX_VALUE;
for(int j=i+1;j<=n;j++)
{
int t=getdis(s[i],s[j]);
G[i][j]=G[j][i]=t;
}
}
}

public int prim(){
int sum = 0;
boolean flag[]=new boolean[n+1];
flag[1] = true; //选取第一个卡车进入U集

for(int k=1; k< n; k++){ //循环n-1次,选取n-1条边
int min = Integer.MAX_VALUE,min_i = 1;
for(int i=1; i<=n; i++){
if( !flag[i] && G[1][i] < min){
min = G[1][i];
min_i = i;
}
}

flag[min_i] = true; //
for(int i=1; i<= n; i++){
if( !flag[i] && G[1][i] > G[min_i][i]){
G[1][i] = G[min_i][i];
}
}

sum += G[1][min_i];//加上权值
}

return sum;

}
}

源码下载:
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值