题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1102
一;利用kruscal算法:
利用到了并查集的思想。getParent()利用是一种两趟方法(two-path method),一趟是沿查找路径上升,直到找到根,第二趟是沿路径下降,以便更新每个节点使之直接指向根。
另外按rank合并没有体现,其思想是为每个节点添加一个rank,好让合并的时候节点较少的节点直接指向节点较多的节点。
int N;
int len=0;
int parent[105];
struct Edge{
int a,b,v;
}edges[5000];
int cmp(const Edge& lhs,const Edge& rhs){
return lhs.v<rhs.v;
}
int getParent(int x){
if(parent[x]!=x){
parent[x]=getParent(parent[x]);
}
return parent[x];
}
void unon(int x,int y){
int u=getParent(x);
int v=getParent(y);
if(u!=v){
parent[u]=v;
}
}
int kruscal(){
int res=0;
sort(edges+1,edges+len+1,cmp);
for(int i=1;i<=N;++i){
int u=getParent(edges[i].a);
int v=getParent(edges[i].b);
if(u!=v){
res+=edges[i].v;
unon(u,v);
}
}
return res;
}
int main()
{
freopen("in.txt","r",stdin);
int n,i,j,tmp;
while(scanf("%d",&N)!=EOF)
{
len=0;
for(i=1;i<=N;i++)
for(j=1;j<=N;j++){
if(j>i){
edges[len].a=i;
edges[len].b=j;
cin>>edges[len].v;
len++;
}else{
cin>>tmp;
}
}
scanf("%d",&n);
//初始化父亲数组
for(int i=1;i<=N;++i){
parent[i]=i;
}
while(n--)
{
int u,v;
scanf("%d%d",&u,&v);
unon(getParent(u),getParent(v));
}
cout<< kruscal()<<endl;
}
system("pause");
return 0;
}
二,利用prim算法:从一点出发,依次寻找最短的,同时更新到已经连通区域的最短路径的长度(即未连通点到已加入连通集合点的最短边);
int Prim(){
memset(vis,false,sizeof(vis));
int res=0;
for(int i=1;i<=N;++i){
cost[i]=map[1][i];
}
vis[1]=true;
for(int i=1;i<N;++i){
int min=INT_MAX;
int p=-1;
for(int j=1;j<=N;++j){
if(!vis[j]&&min>cost[j]){
p=j;min=cost[j];
}
}
if(min==INT_MAX) return -1;
vis[p]=true;
res+=min;
for(int j=1;j<=N;++j){
if(cost[j]>map[p][j]){
cost[j]=map[p][j];
}
}
}
return res;
}