有向图最小生成树

int pre[maxn];//最短弧前驱
int vis[maxn];//点标记
int used[maxn];//查环过程的标记
double Map[maxn][maxn];//存图关系
int n,m,u,v,len;

double zhuliu(int root)
{
    double sum=0;
    int i,j,k;
    memset(vis,0,sizeof vis);
    while(1){
        for(i=1;i<=n;i++){  //1、求最短弧集合pre
            if(vis[i]||i==root) continue;
            pre[i]=i;
            for(int j=1;j<=n;j++)   //找i点的最短前驱弧
                if(!vis[j]&&Map[j][i]<Map[pre[i]][i])
                    pre[i]=j;
            if(pre[i]==i) return -1;    //弱图不连通
        }
        for(i=1;i<=n;i++){  //2、查环
            if(vis[i]||i==root) continue;
            memset(used,0,sizeof used);
            used[root]=1;
            k=i;
            while(!used[k]){
                used[k]=1;
                k=pre[k];
            }
            if(k!=root) break;//存在环
        }
        if(i>n){     //不存在环了
            for(j=1;j<=n;j++)
                if(j!=root&&!vis[j])
                    sum+=Map[pre[j]][j];
            return sum;
        }
        i=k;  //3、下面将这个环缩到i点;
        do{   //4、先累加环记录下环权值
            sum+=Map[pre[k]][k];
            k=pre[k];
        }while(k!=i);
        do{//5、修改环上点的前驱边,为准备环收缩
            for(j=1;j<=n;j++)
                if(!vis[j]&&Map[j][k]<INF&&j!=pre[k])
                    Map[j][k]-=Map[pre[k]][k];
            k=pre[k];
        }while(k!=i);
        for(j=1;j<=n;j++){       //6、环收缩到i点
            if(j==i||vis[j])continue;
            for(k=pre[i];k!=i;k=pre[k]){        //k点的对外距离给i点
                if(Map[i][j]>Map[k][j])Map[i][j]=Map[k][j];
                if(Map[j][i]>Map[j][k])Map[j][i]=Map[j][k];
            }
        }
        for(k=pre[i];k!=i;k=pre[k])vis[k]=1;//7、将环上除i外全标记
    }
}

猜你喜欢

转载自blog.csdn.net/qq_40679299/article/details/83627378