次小生成树 prim和kruskal

prim:
  先用prim求出最小生成树T,在prim的同时,用一个矩阵maxd[u][v] 记录 在T中连结任意两点u,v的唯一的路中权值最大的那条边的权值,这是很容易做到的,因为prim是每次增加一个结点s, 在此需要保存节点和其父节点,采用DP,则最大权值要么是新加入的边,要么是父节点到起始点的采用DP算出来的距离。即:
  maxd[j][p] = max[p][j] = lowc[p] > max[j][closest[p]] ? lowc[p] : max[j][closest[p]] ;
  枚举所有不在T中的边uv, 加入边uv则必然替换权为maxd[u][v]的边,这样才能保证次小。

const int INF=0x3f3f3f3f;
const int MAXN=110;
bool vis[MAXN],used[MAXN][MAXN];
int lowc[MAXN],closest[MAXN],maxd[MAXN][MAXN];
int Prim(int cost[][MAXN],int n)//点是0~n-1
{
    int ans=0;
    memset(vis,false,sizeof(vis));
    vis[0]=true;
    lowc[0]=0;
    for(int i=1; i
    {
        lowc[i]=cost[0][i];//初始点到各点的距离
        closest[i]=1;
    }
    for(int i=1; i
    {
        int minc=INF;
        int p=-1;
        for(int j=0; j
            if(!vis[j]&&minc>lowc[j])
            {
                minc=lowc[j];
                p=j;
            }
        if(minc==INF)return -1;//原图不连通
        ans+=minc;
        vis[p]=true;//p点已访问
        used[p][closest[p]]=used[closest[p]][p]=true;
        for(int j=0; j
        {
            ///重点
            if(vis[j]&&j!=p)
            {
                maxd[j][p] = maxd[p][j] = lowc[p] > maxd[j][closest[p]] ? lowc[p] : maxd[j][closest[p]] ;
            }
            if(!vis[j]&&lowc[j]>cost[p][j])
            {
                lowc[j]=cost[p][j];//p点到各点的距离
                closest[j]=p;
            }
        }
    }
    return ans;
}

还有一步枚举,这里就不写了。

kruskal:
  多次求最小树: 首先,用kruskal求得最小生成树,并用visit数组记录最小生成树的边,假设为总共num条 然后,循环求最小生成树num次,每次都不用第一次求得的最小生成树的边
  假设:第一次求最小生成树用到了 1、2、4这三条边,总共5条边,那循环3次的时候,每次分别不用1、2、4求得最小生成树的MST,最小的MST即为次小生成树。

#include
#include
#include
#include
using namespace std;
#define M 99999999
int n, m,w;
int f[10005], sum, cou;
int visit[10005];

struct edge
{
    int u;
    int v;
    int w;
};

edge e[10005];
void init()
{
    int i;
    for (i = 1; i <= n; i++)
    {
        f[i] = i;
    }
}
int cmp(edge a, edge b)
{
    return a.wint getf(int v)
{
    if (f[v] == v)
        return v;
    else
    {
        f[v] = getf(f[v]);
        return f[v];
    }
}

int merg(int v, int u)
{
    int t1, t2;
    t1 = getf(v);
    t2 = getf(u);
    if (t1 != t2)
    {
        f[t2] = t1;
        return 1;
    }
    return 0;
}
int mintree()
{
    int i,flag;
    init();
    flag = 0;
    w = 0;
    cou = 0;
    for (i = 1; i <= m; i++)
    {
        if (merg(e[i].v, e[i].u))
        {
            cou++;
            visit[w++] = i;
        }
        if (cou == n - 1)
        {
            flag = 1;
            break;
        }
    }
    //cout << sum << endl;
    return  flag ;
}
///重点
int cimintree()
{
    int j, flag,min;
    min = M;
    for (int i = 0; i < w; i++)
    {
        flag = 0;
        init();
        cou = 0;
        sum = 0;
        for (j = 1; j <= m; j++)
        {
            if (j != visit[i])
            {
                if (merg(e[j].v, e[j].u))
                {
                    cou++;
                    sum = sum + e[j].w;
                }
                if (cou == n - 1)
                {
                    flag = 1;
                    break;
                }
            }
        }
        if (flag&&sum < min) min = sum;
    }
    min = (min == M) ? -1 : min;
    return min;
}
int main()
{
    int i,flag,min;
    while (scanf("%d %d", &n,&m) != EOF)
    {
        if (n == 0)
            break;
        sum = 0;
        cou = 0;
        memset(e, 0, sizeof(e));
        memset(f, 0, sizeof(f));
        for (i = 1; i <= m; i++)
        {
            scanf("%d %d %d", &e[i].u, &e[i].v, &e[i].w);
        }
        sort(e + 1, e + m + 1, cmp);
        flag = mintree();
        if (flag == 0)
        {
            cout << "-1" << endl;
        }
        else
        {
            min = cimintree();
            cout << min << endl;
        }
    }
    return 0;
}

你可能感兴趣的:(知识点,编程)