说明:此次作业只为熟悉两种求最小生成树的算法:prim算法(第一次写,邻接表实现,发现写起来也比较简单) 和kruskal算法(这个算法的并查集版本写了好几遍了)
要注意的是当使用表达式做角标时,一定要注意对应关系。。。
code:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#define N 1000001
#define M 0x7fffffff
using namespace std;
int A[N],U[N],V[N],P[N];
typedef struct en{
int id,val;
struct en *next;
}EN;
typedef struct{
int id,w,x,y;
}TEM;
TEM tem;
typedef struct HN{
int id,f;//id-点的编号,f-标记点是否已入'S'集合
EN *fe;
}HN;
HN hn[52];
void createedge(int x,int y,int w){
EN *p;
p=(EN *)malloc(sizeof(EN));
p->id=y;
p->val=w;
p->next=hn[x].fe;
hn[x].fe=p;
p=(EN *)malloc(sizeof(EN));
p->id=x;
p->val=w;
p->next=hn[y].fe;
hn[y].fe=p;
}
int mst_prim_adjl(int n){//prim算法构造最小生成树,邻接表存储
int i,j,s=0;
EN *p;
hn[1].f=1;
for(i=0;i<n-1;i++){
for(tem.w=M,j=1;j<=n;j++){
if(hn[j].f){//已录点
p=hn[j].fe;
while(p){
if((!hn[p->id].f)&&tem.w>p->val){
tem.w=p->val;
tem.id=p->id;
}
p=p->next;
}
}
}
//printf("id:%d tem.w:%d\n",tem.id,tem.w);
hn[tem.id].f=1;
s+=tem.w;
}
return s;
}
int fa(int x){return (P[x]==-1?x:(P[x]=fa(P[x])));}
int mst_kruskal(int en,int pn){
int x,y,tem,i,j,t,s=0,k=0;
for(i=0;i<en-1;i++){
for(t=i,j=i+1;j<en;j++)
if(A[t]>A[j])t=j;
if(t!=i){
tem=A[i];A[i]=A[t];A[t]=tem;
tem=U[i];U[i]=U[t];U[t]=tem;
tem=V[i];V[i]=V[t];V[t]=tem;
}
}
//for(i=0;i<en;i++)printf("%d\n",A[i]);
for(i=0;i<pn;i++)P[i]=-1;
for(i=0;i<en;i++){
x=fa(U[i]);
y=fa(V[i]);
if(x!=y){
P[x]=y;
s+=A[i];
k++;
//printf("point:%d %d value:%d\n",U[i],V[i],A[i]);
}
//if(k==pn-1)break;
}
return s;
}
int main(){
int m,b,n,i,j,minv,k;
int u,v,t,q;
scanf("%d",&k);
while(k--){
scanf("%d %d",&m,&b);
if(!b){
q=0;
for(i=0;i<m;i++)
for(j=0;j<m;j++){
scanf("%d",&t);
if(t&&j>i){
A[q]=t;
U[q]=i;
V[q]=j;
q++;
}
}
// printf("%d\n",q);
minv=mst_kruskal(q,m);
}
else{
for(i=1;i<52;i++){
hn[i].fe=NULL;
hn[i].f=0;
hn[i].id=i+1;
}
for(i=0;i<m;i++){
scanf("%d %d %d",&u,&v,&t);
createedge(u,v,t);
if(u>v)n=u;
else n=v;
}
minv=mst_prim_adjl(n);
}
printf("%d\n",minv);
}
return 0;
}