xtu_exam 1018 最小生成树

说明:此次作业只为熟悉两种求最小生成树的算法: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;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值