码迷,mamicode.com
首页 > 其他好文 > 详细

次小生成树【模板】

时间:2015-05-03 00:49:11      阅读:187      评论:0      收藏:0      [点我收藏+]

标签:

给一个图,判断图的最小生成树是否唯一。
End[]记录邻接表尾节点的位置。MST表示最小生成树的大小,SecMST表示次小生成树的大小。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN = 1010;
const int MAXM = 100010;

int father[MAXN];

int find(int x)
{
    if(x != father[x])
        father[x] = find(father[x]);
    return father[x];
}

struct Node
{
    int from;
    int to;
    int w;
    bool vis;
};
Node Edges[MAXM];//存储边信息

bool cmp(Node a, Node b)
{
    return a.w < b.w;
}

//链式前向星
struct Node1
{
    int to;
    int next;
};
Node1 Vertex[MAXN];//边数组,表示结点连向的边

int N,M;
int head[MAXN];     //邻接表头结点位置
int End[MAXN];      //邻接表尾结点位置,方便合并
int Len[MAXN][MAXN];//图中两点之间在最小生成树上路径最长的边

void Kruskal()
{
    int x,y,k = 0;
    int ans = 0;

    //初始化邻接表,每个节点初始的时候添加一条指向自己的边,表示结点i各自为一个集合
    memset(head,-1,sizeof(head));   
    memset(End,-1,sizeof(End));
    for(int i = 1; i <= N; i++)
    {
        Vertex[i].to = i;
        Vertex[i].next = head[i];
        End[i] = i;
        head[i] = i;
    }

    sort(Edges,Edges+M,cmp);//边按权值排序
    for(int i = 0; i < M; i++)
    {
        if(k == N-1)
            break;
        if(Edges[i].w < 0)
            continue;
        x = find(Edges[i].from);
        y = find(Edges[i].to);
        if(x != y)
        {
            //遍历两个节点所在的集合
            for(int w = head[x]; w != -1; w = Vertex[w].next)
            {
                for(int v = head[y]; v != -1; v = Vertex[v].next)
                {
                    Len[Vertex[w].to][Vertex[v].to] = Len[Vertex[v].to][Vertex[w].to] = Edges[i].w;
                    //当前加入的边一定是加(x,y)边成环后删去的除(x,y)外长度最大的边
                }
            }
            Vertex[End[y]].next = head[x];//合并两个邻接表,表示两点已连边连在一个集合中,最终连成一个最小生成树
            head[x] = head[y];
            End[y] = End[x];
            father[y] = x;
            k++;
            Edges[i].vis = true;
        }
    }
}

int main()
{
    int T,x,y,w;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&N,&M);
        for(int i = 1; i <= N; i++)
            father[i] = i;
        memset(Len,0x7f,sizeof(Len));
        for(int i = 0; i < M; i++)
        {
            scanf("%d%d%d",&x,&y,&w);
            Edges[i].from = x;
            Edges[i].to = y;
            Edges[i].w = w;
            Edges[i].vis = false;
        }

        int MST,SecMST;
        Kruskal();
        MST = 0;//最小生成树长度
        for(int i = 0; i < M; i++)
        {
            if(Edges[i].vis)
                MST += Edges[i].w;
        }
        SecMST = 0xfffff0;
        for(int i = 0; i < M; i++)
        {
            if(!Edges[i].vis)//加边,并删去最小生成树上的边
                SecMST = min(SecMST,MST+Edges[i].w - Len[Edges[i].from][Edges[i].to]);
        }
        if(SecMST == MST)
            printf("Not Unique!\n");
        else
            printf("%d\n",MST);
    }

    return 0;
}

次小生成树【模板】

标签:

原文地址:http://blog.csdn.net/lianai911/article/details/45445715

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!