最小生成树及其衍生



          今天学了最小生成树的概念以及他的两个算法:PrimeKruskal

Prime:将整个图分为两个连通分量,则连接两个分量的线当中权值最小的边一定在最小生成树中,因为两个连通分量中的各个点互相连通,所以需要一条边使两个分量相连,则权值越小越好。

步骤:先任选一个点加入集合中,设数组dis[i]i到集合的最小距离。

        每次在dis[]中选择距离最小的点加入集合并更新dis[],直到有N-1条边。


Kruskal:将所有的边从小到大排序,每次选择最小的边加入树中,

u,v在不同的连通分量里(可用并查集判断)。加满N-1条边结束。

/*若题目已给出部分边,可在Prime中把权值设为0,也可在Kruskal

/*中把u,v弄为同一个连通分量(同时可判断加入的边里有哪些属于最小生成树)。


次小生成树:连通图里权值和仅次于最小生成树的树,与最小生成树只相差了一条边。因为最小生成树任意两个分量之间的边一定是最小的,所以只需要替换其中一条边就可的到次小,如果相差多条边的话,那么一定有处于两者中间的树。

  1. 建立最小生成树,并用DP求出最小生成树中u,v两点间的路中权值最大的那条路的权值,最小生成树的权值和为ans.

  2. 枚举所有不在最小生成树里的边(可在1操作中使用used数组记录,记录每一个节点的pre节点)。

  3. 因为只要求每个点直接或间接相连即可,而不要求一笔走完,所以为了实现次小,替换u,v中权值最大的边(u,v有直接相连的边且此边不在最小生成树中),找到枚举完后的最小值,minn

    minnans进行比较,若相等,即不为唯一树,反之。

  4. 代码(Poj 1679):#include
    #include
    const int MAXN=550,INF=0x3f3f3f3f;
    int n,m,max[MAXN][MAXN],f[MAXN][MAXN],flag[MAXN],used[MAXN][MAXN],pre[MAXN];
    int xiao(int x,int y){
     if(x>y) return y; return x;
    }
    int da(int x,int y){
     if(x>y) return x; return y;
    }
    int Prime(int f[][MAXN]){
     int dis[MAXN],i,ans=0,j;
     memset(dis,0x3f,sizeof(dis));
     memset(used,false,sizeof(used));
     memset(max,0,sizeof(max));
     memset(flag,false,sizeof(flag));
     dis[1]=0; flag[1]=true; pre[1]=-1;
     for(i=1;i<=n;i++){
      if(f[1][i]!=0 && f[1][i]     dis[i]=f[1][i]; pre[i]=1;
      } 
     }
     for(i=1;i   int min=INF,t;
      for(j=1;j<=n;j++){
       if(flag[j]==false && min>dis[j]){
        min=dis[j]; t=j;
       }
      }
      used[t][pre[t]]=used[pre[t]][t]=true;
      ans+=dis[t];
      flag[t]=true;
      for(j=1;j<=n;j++){
       if(flag[j]==true) max[j][t]=max[t][j]=da(dis[t],max[j][pre[t]]);
       if(flag[j]==false && f[t][j]     dis[j]=f[t][j]; pre[j]=t;
       }
      }
     }
     
     return ans;
    }
    int pd(int ans){
     int i,j,minn=INF;
     for(i=1;i<=n;i++){
      for(j=i+1;j<=n;j++){
       if(f[i][j]!=INF && used[i][j]==false){
        minn=xiao(minn,ans+f[i][j]-max[i][j]);
       }
      }
     }
     return minn;
    }
    int main(){
     freopen("in.txt","r",stdin);
     int T; scanf("%d",&T);
     while(T--){
      scanf("%d%d",&n,&m);
      if(n==1){
       printf("0\n"); continue;
      }
      int i,j,ans;
      for(i=1;i<=n;i++)
      for(j=1;j<=n;j++){
       if(i==j) f[i][j]=0;
       f[i][j]=INF;
      }
      for(i=1;i<=m;i++){
       int xi,yi,ci; scanf("%d%d%d",&xi,&yi,&ci);
       f[xi][yi]=f[yi][xi]=ci;
      }
      ans=Prime(f);
      if(ans==pd(ans)) printf("Not Unique!\n");
      else printf("%d\n",ans);
     }
    }

你可能感兴趣的:(最小生成树及其衍生)