次小生成树 附 poj1679The Unique MST

来源:互联网 发布:c语言双引号if 编辑:程序博客网 时间:2024/06/17 22:50


 次小生成树,可通过最小生成树求得。最小生成树得到后,把某一未利用的边加入树中,则会形成一个环,把这个环上其余的最大边去掉,就会得到这个加入这个边的次小生成树。把所有的未利用的边遍历,取最小值,就会得到次小生成树。


附poj1679的代码:


#include<iostream>#include<cstdio>#include<cstring>using namespace std;const int maxn=105;const int INF=100000000;int map[maxn][maxn],used[maxn],minn[maxn];//prim所用数组int in[maxn][maxn],pre[maxn],path[maxn][maxn];//求次小新增数组,pre为新插入节点的前驱     //in数组记录i,j的变之间是否被利用,path表示变未被利用的两点之间已经形成的路径的最大边值     int T;int n,m;int x,y,z;int prim(){    memset(used,0,sizeof(used));    memset(in,0,sizeof(in));    memset(pre,0,sizeof(pre));    int ans=0;    for(int i=1;i<=n;++i) minn[i]=INF;    minn[1]=0;    for(int i=0;i<n;++i){        int k=-1;        for(int j=1;j<=n;++j){            if(!used[j]&&(k==-1||minn[j]<minn[k]))            k=j;        }      //与原来的prim算法不同的地方        int p=pre[k];   //找到前驱        in[p][k]=in[k][p]=1;    //边被利用        path[p][k]=path[k][p]=minn[k];//相邻的节点的最大距离就是边长        for(int j=1;j<=n;++j)            if(used[j]){  //更新已经存在的点                path[j][k]=path[k][j]=max(path[j][p],map[p][k]);            //用新加入的边更新之前的最大值            }        used[k]=1;        ans+=minn[k];        for(int j=1;j<=n;++j){            if(!used[j]&&map[k][j]<minn[j]){                minn[j]=map[k][j];                pre[j]=k;  //比prim多的部分,求前驱节点            }        }    }    return ans;}int main(){    scanf("%d",&T);    while(T--){        scanf("%d%d",&n,&m);        for(int i=1;i<=n;i++)            for(int j=1;j<=n;j++)                map[i][j]=map[j][i]=INF;        while(m--){            scanf("%d%d%d",&x,&y,&z);            map[x][y]=map[y][x]=z;        }        int ans=prim();        int ok=1;        for(int i=1;i<=n&&ok;i++){            for(int j=1;j<=n&&ok;j++){                if(map[i][j]!=INF&&!in[i][j])                    if(ans==ans-map[i][j]+path[i][j])                        ok=0;            }        }        if(ok) printf("%d\n",ans);        else printf("Not Unique!\n");    }    return 0;}